@smthrs/observability 0.35.0 → 1.0.0-rc.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/LICENSE +1 -1
- package/README.md +87 -0
- package/dist/cjs/BrowserOtel.d.ts +37 -0
- package/dist/cjs/BrowserOtel.d.ts.map +1 -0
- package/dist/cjs/BrowserOtel.js +47 -0
- package/dist/cjs/BrowserOtel.js.map +7 -0
- package/dist/cjs/Endpoint.d.ts +70 -0
- package/dist/cjs/Endpoint.d.ts.map +1 -0
- package/dist/cjs/Endpoint.js +85 -0
- package/dist/cjs/Endpoint.js.map +7 -0
- package/dist/cjs/JournalLogger.d.ts +232 -0
- package/dist/cjs/JournalLogger.d.ts.map +1 -0
- package/dist/cjs/JournalLogger.js +415 -0
- package/dist/cjs/JournalLogger.js.map +7 -0
- package/dist/cjs/Logger.d.ts +56 -0
- package/dist/cjs/Logger.d.ts.map +1 -0
- package/dist/cjs/Logger.js +72 -0
- package/dist/cjs/Logger.js.map +7 -0
- package/dist/cjs/Metric.d.ts +67 -0
- package/dist/cjs/Metric.d.ts.map +1 -0
- package/dist/cjs/Metric.js +68 -0
- package/dist/cjs/Metric.js.map +7 -0
- package/dist/cjs/NodeOtel.d.ts +42 -0
- package/dist/cjs/NodeOtel.d.ts.map +1 -0
- package/dist/cjs/NodeOtel.js +78 -0
- package/dist/cjs/NodeOtel.js.map +7 -0
- package/dist/cjs/Otel.d.ts +63 -0
- package/dist/cjs/Otel.d.ts.map +1 -0
- package/dist/cjs/Otel.js +75 -0
- package/dist/cjs/Otel.js.map +7 -0
- package/dist/cjs/Otlp.d.ts +203 -0
- package/dist/cjs/Otlp.d.ts.map +1 -0
- package/dist/cjs/Otlp.js +251 -0
- package/dist/cjs/Otlp.js.map +7 -0
- package/dist/cjs/Resource.d.ts +163 -0
- package/dist/cjs/Resource.d.ts.map +1 -0
- package/dist/cjs/Resource.js +186 -0
- package/dist/cjs/Resource.js.map +7 -0
- package/dist/cjs/index.d.ts +61 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +47 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/schemaIssuePath.d.ts +31 -0
- package/dist/cjs/internal/schemaIssuePath.d.ts.map +1 -0
- package/dist/cjs/internal/schemaIssuePath.js +49 -0
- package/dist/cjs/internal/schemaIssuePath.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/BrowserOtel.d.ts +37 -0
- package/dist/esm/BrowserOtel.d.ts.map +1 -0
- package/dist/esm/BrowserOtel.js +24 -0
- package/dist/esm/BrowserOtel.js.map +1 -0
- package/dist/esm/Endpoint.d.ts +70 -0
- package/dist/esm/Endpoint.d.ts.map +1 -0
- package/dist/esm/Endpoint.js +110 -0
- package/dist/esm/Endpoint.js.map +1 -0
- package/dist/esm/JournalLogger.d.ts +232 -0
- package/dist/esm/JournalLogger.d.ts.map +1 -0
- package/dist/esm/JournalLogger.js +520 -0
- package/dist/esm/JournalLogger.js.map +1 -0
- package/dist/esm/Logger.d.ts +56 -0
- package/dist/esm/Logger.d.ts.map +1 -0
- package/dist/esm/Logger.js +61 -0
- package/dist/esm/Logger.js.map +1 -0
- package/dist/esm/Metric.d.ts +67 -0
- package/dist/esm/Metric.d.ts.map +1 -0
- package/dist/esm/Metric.js +80 -0
- package/dist/esm/Metric.js.map +1 -0
- package/dist/esm/NodeOtel.d.ts +42 -0
- package/dist/esm/NodeOtel.d.ts.map +1 -0
- package/dist/esm/NodeOtel.js +56 -0
- package/dist/esm/NodeOtel.js.map +1 -0
- package/dist/esm/Otel.d.ts +63 -0
- package/dist/esm/Otel.d.ts.map +1 -0
- package/dist/esm/Otel.js +52 -0
- package/dist/esm/Otel.js.map +1 -0
- package/dist/esm/Otlp.d.ts +203 -0
- package/dist/esm/Otlp.d.ts.map +1 -0
- package/dist/esm/Otlp.js +384 -0
- package/dist/esm/Otlp.js.map +1 -0
- package/dist/esm/Resource.d.ts +163 -0
- package/dist/esm/Resource.d.ts.map +1 -0
- package/dist/esm/Resource.js +238 -0
- package/dist/esm/Resource.js.map +1 -0
- package/dist/esm/index.d.ts +61 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +61 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/schemaIssuePath.d.ts +31 -0
- package/dist/esm/internal/schemaIssuePath.d.ts.map +1 -0
- package/dist/esm/internal/schemaIssuePath.js +59 -0
- package/dist/esm/internal/schemaIssuePath.js.map +1 -0
- package/docs/README.md +164 -0
- package/docs/api.md +780 -0
- package/docs/concepts/instrumentation-and-export.md +98 -0
- package/docs/concepts/layer-map.md +73 -0
- package/docs/concepts/validated-acquisition.md +106 -0
- package/docs/guides/export-to-a-collector.md +190 -0
- package/docs/guides/forward-logs-to-the-journal.md +226 -0
- package/docs/guides/install-a-logger.md +111 -0
- package/docs/guides/read-runtime-metrics.md +83 -0
- package/docs/guides/testing.md +134 -0
- package/docs/guides/wire-an-opentelemetry-sdk.md +226 -0
- package/docs/installation.md +102 -0
- package/docs/quickstart.md +145 -0
- package/docs/troubleshooting.md +168 -0
- package/package.json +221 -32
- package/src/BrowserOtel.ts +51 -0
- package/src/Endpoint.ts +131 -0
- package/src/JournalLogger.ts +635 -0
- package/src/Logger.ts +107 -0
- package/src/Metric.ts +88 -0
- package/src/NodeOtel.ts +90 -0
- package/src/Otel.ts +118 -0
- package/src/Otlp.ts +514 -0
- package/src/Resource.ts +325 -0
- package/src/index.ts +67 -0
- package/src/internal/schemaIssuePath.ts +65 -0
- package/docker-compose.otel.yml +0 -104
- package/grafana/dashboards/smithers-dashboard.json +0 -453
- package/grafana/provisioning/dashboards/dashboards.yml +0 -12
- package/grafana/provisioning/datasources/datasources.yml +0 -49
- package/loki/loki-config.yaml +0 -35
- package/otel-collector-config.yml +0 -38
- package/prometheus/prometheus.yml +0 -8
- package/src/MetricName.ts +0 -1
- package/src/MetricsServiceLive.js +0 -9
- package/src/README.md +0 -28
- package/src/ResolvedSmithersObservabilityOptions.ts +0 -12
- package/src/SmithersEvent.ts +0 -843
- package/src/SmithersLogFormat.ts +0 -1
- package/src/SmithersMetricDefinition.ts +0 -15
- package/src/SmithersMetricType.ts +0 -1
- package/src/SmithersMetricUnit.ts +0 -1
- package/src/SmithersObservability.js +0 -15
- package/src/SmithersObservabilityOptions.ts +0 -12
- package/src/SmithersObservabilityService.ts +0 -13
- package/src/_coreCorrelation/CorrelationContext.ts +0 -10
- package/src/_coreCorrelation/CorrelationContextLive.js +0 -11
- package/src/_coreCorrelation/CorrelationContextService.js +0 -15
- package/src/_coreCorrelation/CorrelationContextServiceShape.ts +0 -12
- package/src/_coreCorrelation/CorrelationPatch.ts +0 -3
- package/src/_coreCorrelation/README.md +0 -20
- package/src/_coreCorrelation/_correlationStorage.js +0 -4
- package/src/_coreCorrelation/correlationContextFiberRef.js +0 -5
- package/src/_coreCorrelation/correlationContextToLogAnnotations.js +0 -18
- package/src/_coreCorrelation/getCurrentCorrelationContext.js +0 -9
- package/src/_coreCorrelation/getCurrentCorrelationContextEffect.js +0 -11
- package/src/_coreCorrelation/index.js +0 -14
- package/src/_coreCorrelation/mergeCorrelationContext.js +0 -51
- package/src/_coreCorrelation/runWithCorrelationContext.js +0 -14
- package/src/_coreCorrelation/updateCurrentCorrelationContext.js +0 -17
- package/src/_coreCorrelation/withCorrelationContext.js +0 -38
- package/src/_coreCorrelation/withCurrentCorrelationContext.js +0 -11
- package/src/_coreMetrics.js +0 -14
- package/src/_coreMetricsShape.ts +0 -44
- package/src/_corePrometheus.js +0 -91
- package/src/_corePrometheusShape.ts +0 -11
- package/src/_coreTracing.js +0 -132
- package/src/_coreTracingShape.ts +0 -17
- package/src/_otelLogBuilders.js +0 -102
- package/src/_sessionFileResolvers.js +0 -164
- package/src/_smithersSpanAttributeAliases.js +0 -19
- package/src/_smithersTraceSpanStorage.js +0 -3
- package/src/_traceEventNormalizers.js +0 -499
- package/src/_traceRedaction.js +0 -162
- package/src/agentSessionEventToOtelLogRecord.js +0 -55
- package/src/agentTrace.ts +0 -144
- package/src/agentTraceCapabilities.js +0 -151
- package/src/annotateSmithersTrace.js +0 -11
- package/src/canonicalTraceEventToOtelLogRecord.js +0 -55
- package/src/correlation.js +0 -56
- package/src/createSmithersObservabilityLayer.js +0 -59
- package/src/createSmithersOtelLayer.js +0 -23
- package/src/createSmithersRuntimeLayer.js +0 -2
- package/src/detectAgentFamily.js +0 -26
- package/src/detectCaptureMode.js +0 -29
- package/src/emitOtelLogRecord.js +0 -19
- package/src/getCurrentSmithersTraceAnnotations.js +0 -14
- package/src/getCurrentSmithersTraceSpan.js +0 -7
- package/src/index.d.ts +0 -1392
- package/src/index.js +0 -137
- package/src/kindPhase.js +0 -17
- package/src/logging.js +0 -264
- package/src/makeSmithersSpanAttributes.js +0 -20
- package/src/metrics/README.md +0 -22
- package/src/metrics/SmithersMetricDefinition.ts +0 -17
- package/src/metrics/SmithersMetricType.ts +0 -1
- package/src/metrics/SmithersMetricUnit.ts +0 -1
- package/src/metrics/_asyncExternalWaitCounts.js +0 -4
- package/src/metrics/_buckets.js +0 -37
- package/src/metrics/_incrementGauge.js +0 -11
- package/src/metrics/_processStartMs.js +0 -1
- package/src/metrics/activeNodes.js +0 -2
- package/src/metrics/activeRuns.js +0 -2
- package/src/metrics/agentActionsTotal.js +0 -2
- package/src/metrics/agentDurationMs.js +0 -3
- package/src/metrics/agentErrorsTotal.js +0 -2
- package/src/metrics/agentEventsTotal.js +0 -2
- package/src/metrics/agentInvocationsTotal.js +0 -2
- package/src/metrics/agentRetriesTotal.js +0 -2
- package/src/metrics/agentSessionsTotal.js +0 -2
- package/src/metrics/agentTokensTotal.js +0 -2
- package/src/metrics/alertDeliveriesAttempted.js +0 -2
- package/src/metrics/alertDeliveriesSuppressed.js +0 -2
- package/src/metrics/alertsAcknowledgedTotal.js +0 -2
- package/src/metrics/alertsActive.js +0 -2
- package/src/metrics/alertsEscalatedTotal.js +0 -2
- package/src/metrics/alertsFiredTotal.js +0 -2
- package/src/metrics/alertsReopenedTotal.js +0 -2
- package/src/metrics/alertsResolvedTotal.js +0 -2
- package/src/metrics/alertsSilencedTotal.js +0 -2
- package/src/metrics/approvalPending.js +0 -2
- package/src/metrics/approvalWaitDuration.js +0 -5
- package/src/metrics/approvalsDenied.js +0 -2
- package/src/metrics/approvalsGranted.js +0 -2
- package/src/metrics/approvalsRequested.js +0 -2
- package/src/metrics/attemptDuration.js +0 -3
- package/src/metrics/attentionBacklog.js +0 -2
- package/src/metrics/cacheHits.js +0 -2
- package/src/metrics/cacheMisses.js +0 -2
- package/src/metrics/dbQueryDuration.js +0 -3
- package/src/metrics/dbRetries.js +0 -2
- package/src/metrics/dbTransactionDuration.js +0 -3
- package/src/metrics/dbTransactionRetries.js +0 -2
- package/src/metrics/dbTransactionRollbacks.js +0 -2
- package/src/metrics/devtoolsActiveSubscribers.js +0 -2
- package/src/metrics/devtoolsBackpressureDisconnectTotal.js +0 -2
- package/src/metrics/devtoolsDeltaBuildMs.js +0 -3
- package/src/metrics/devtoolsEventBytes.js +0 -3
- package/src/metrics/devtoolsEventTotal.js +0 -2
- package/src/metrics/devtoolsSnapshotBuildMs.js +0 -5
- package/src/metrics/devtoolsSubscribeTotal.js +0 -2
- package/src/metrics/errorsTotal.js +0 -2
- package/src/metrics/eventsEmittedTotal.js +0 -2
- package/src/metrics/externalWaitAsyncPending.js +0 -2
- package/src/metrics/gatewayApprovalDecisionsTotal.js +0 -2
- package/src/metrics/gatewayAuthEventsTotal.js +0 -2
- package/src/metrics/gatewayConnectionsActive.js +0 -2
- package/src/metrics/gatewayConnectionsClosedTotal.js +0 -2
- package/src/metrics/gatewayConnectionsTotal.js +0 -2
- package/src/metrics/gatewayCronTriggersTotal.js +0 -2
- package/src/metrics/gatewayErrorsTotal.js +0 -2
- package/src/metrics/gatewayHeartbeatTicksTotal.js +0 -2
- package/src/metrics/gatewayMessagesReceivedTotal.js +0 -2
- package/src/metrics/gatewayMessagesSentTotal.js +0 -2
- package/src/metrics/gatewayRpcCallsTotal.js +0 -2
- package/src/metrics/gatewayRpcDuration.js +0 -3
- package/src/metrics/gatewayRunEventBackpressureDisconnectTotal.js +0 -4
- package/src/metrics/gatewayRunsCompletedTotal.js +0 -2
- package/src/metrics/gatewayRunsStartedTotal.js +0 -2
- package/src/metrics/gatewaySignalsTotal.js +0 -2
- package/src/metrics/gatewayWebhooksReceivedTotal.js +0 -2
- package/src/metrics/gatewayWebhooksRejectedTotal.js +0 -2
- package/src/metrics/gatewayWebhooksVerifiedTotal.js +0 -2
- package/src/metrics/heartbeatDataSizeBytes.js +0 -5
- package/src/metrics/heartbeatIntervalMs.js +0 -3
- package/src/metrics/hotReloadDuration.js +0 -3
- package/src/metrics/hotReloadFailures.js +0 -2
- package/src/metrics/hotReloads.js +0 -2
- package/src/metrics/httpRequestDuration.js +0 -3
- package/src/metrics/httpRequests.js +0 -2
- package/src/metrics/index.d.ts +0 -1222
- package/src/metrics/index.js +0 -168
- package/src/metrics/memoryFactReads.js +0 -3
- package/src/metrics/memoryFactWrites.js +0 -3
- package/src/metrics/memoryMessageSaves.js +0 -3
- package/src/metrics/memoryRecallDuration.js +0 -11
- package/src/metrics/memoryRecallQueries.js +0 -3
- package/src/metrics/metricsServiceAdapter.js +0 -181
- package/src/metrics/nodeDuration.js +0 -3
- package/src/metrics/nodeRetriesTotal.js +0 -2
- package/src/metrics/nodesFailed.js +0 -2
- package/src/metrics/nodesFinished.js +0 -2
- package/src/metrics/nodesStarted.js +0 -2
- package/src/metrics/openApiToolCallErrorsTotal.js +0 -3
- package/src/metrics/openApiToolCallsTotal.js +0 -3
- package/src/metrics/openApiToolDuration.js +0 -9
- package/src/metrics/processHeapUsedBytes.js +0 -2
- package/src/metrics/processMemoryRssBytes.js +0 -2
- package/src/metrics/processUptimeSeconds.js +0 -2
- package/src/metrics/promptSizeBytes.js +0 -3
- package/src/metrics/replaysStarted.js +0 -3
- package/src/metrics/responseSizeBytes.js +0 -3
- package/src/metrics/rewindDurationMs.js +0 -3
- package/src/metrics/rewindFramesDeleted.js +0 -3
- package/src/metrics/rewindRollbackTotal.js +0 -2
- package/src/metrics/rewindSandboxesReverted.js +0 -3
- package/src/metrics/rewindTotal.js +0 -2
- package/src/metrics/runDuration.js +0 -3
- package/src/metrics/runForksCreated.js +0 -3
- package/src/metrics/runsAncestryDepth.js +0 -3
- package/src/metrics/runsCancelledTotal.js +0 -2
- package/src/metrics/runsCarriedStateBytes.js +0 -5
- package/src/metrics/runsContinuedTotal.js +0 -2
- package/src/metrics/runsFailedTotal.js +0 -2
- package/src/metrics/runsFinishedTotal.js +0 -2
- package/src/metrics/runsResumedTotal.js +0 -2
- package/src/metrics/runsTotal.js +0 -2
- package/src/metrics/sandboxActive.js +0 -2
- package/src/metrics/sandboxBundleSizeBytes.js +0 -5
- package/src/metrics/sandboxCompletedTotal.js +0 -2
- package/src/metrics/sandboxCreatedTotal.js +0 -2
- package/src/metrics/sandboxDurationMs.js +0 -3
- package/src/metrics/sandboxPatchCount.js +0 -3
- package/src/metrics/sandboxTransportDurationMs.js +0 -5
- package/src/metrics/schedulerConcurrencyUtilization.js +0 -2
- package/src/metrics/schedulerQueueDepth.js +0 -2
- package/src/metrics/schedulerWaitDuration.js +0 -5
- package/src/metrics/scorerDuration.js +0 -9
- package/src/metrics/scorerEventsFailed.js +0 -2
- package/src/metrics/scorerEventsFinished.js +0 -2
- package/src/metrics/scorerEventsStarted.js +0 -2
- package/src/metrics/scorersFailed.js +0 -3
- package/src/metrics/scorersFinished.js +0 -3
- package/src/metrics/scorersStarted.js +0 -3
- package/src/metrics/smithersMetricCatalog.js +0 -893
- package/src/metrics/smithersMetricCatalogByKey.js +0 -2
- package/src/metrics/smithersMetricCatalogByName.js +0 -2
- package/src/metrics/smithersMetricCatalogByPrometheusName.js +0 -4
- package/src/metrics/snapshotDuration.js +0 -9
- package/src/metrics/snapshotsCaptured.js +0 -3
- package/src/metrics/supervisorPollDuration.js +0 -5
- package/src/metrics/supervisorPollsTotal.js +0 -2
- package/src/metrics/supervisorResumeLag.js +0 -5
- package/src/metrics/supervisorResumedTotal.js +0 -2
- package/src/metrics/supervisorSkippedTotal.js +0 -2
- package/src/metrics/supervisorStaleDetected.js +0 -2
- package/src/metrics/taskHeartbeatTimeoutTotal.js +0 -2
- package/src/metrics/taskHeartbeatsTotal.js +0 -2
- package/src/metrics/timerDelayDuration.js +0 -3
- package/src/metrics/timersCancelled.js +0 -2
- package/src/metrics/timersCreated.js +0 -2
- package/src/metrics/timersFired.js +0 -2
- package/src/metrics/timersPending.js +0 -2
- package/src/metrics/toPrometheusMetricName.js +0 -8
- package/src/metrics/tokensCacheReadTotal.js +0 -2
- package/src/metrics/tokensCacheWriteTotal.js +0 -2
- package/src/metrics/tokensContextWindowBucketTotal.js +0 -2
- package/src/metrics/tokensContextWindowPerCall.js +0 -5
- package/src/metrics/tokensInputPerCall.js +0 -3
- package/src/metrics/tokensInputTotal.js +0 -2
- package/src/metrics/tokensOutputPerCall.js +0 -3
- package/src/metrics/tokensOutputTotal.js +0 -2
- package/src/metrics/tokensReasoningTotal.js +0 -2
- package/src/metrics/toolCallErrorsTotal.js +0 -2
- package/src/metrics/toolCallsTotal.js +0 -2
- package/src/metrics/toolDuration.js +0 -3
- package/src/metrics/toolOutputTruncatedTotal.js +0 -2
- package/src/metrics/trackEvent.js +0 -608
- package/src/metrics/updateAsyncExternalWaitPending.js +0 -18
- package/src/metrics/updateProcessMetrics.js +0 -20
- package/src/metrics/vcsDuration.js +0 -3
- package/src/normalizeStructuredEvent.js +0 -15
- package/src/prometheusContentType.js +0 -1
- package/src/renderPrometheusMetrics.js +0 -212
- package/src/resolveAgentTraceCapabilities.js +0 -59
- package/src/resolveSmithersObservabilityOptions.js +0 -109
- package/src/smithersMetrics.js +0 -2
- package/src/smithersSpanNames.js +0 -6
- package/src/unsupportedKindsForCapabilities.js +0 -32
- package/src/withSmithersSpan.js +0 -17
- package/tempo/tempo.yml +0 -17
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Instrumentation and export"
|
|
3
|
+
description: "Why the Smithers packages instrument themselves but export nothing, what that split buys, and the three independent ways to read the same run."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Instrumentation and export are two different jobs, and Smithers puts them in
|
|
9
|
+
different packages on purpose.
|
|
10
|
+
|
|
11
|
+
## Every other package is already instrumented
|
|
12
|
+
|
|
13
|
+
A flow execution opens spans without being asked. The flow lifecycle, the
|
|
14
|
+
engine dispatch, a run claim, a heartbeat, a journal write, down to individual
|
|
15
|
+
SQL statements: each is a span on Effect's own tracer. Alongside
|
|
16
|
+
them, each store package declares and updates its own metric handles on its hot
|
|
17
|
+
paths: `JournalMetrics` in [`@smthrs/journal`](/api/journal), `RunStoreMetrics`
|
|
18
|
+
in [`@smthrs/run-store`](/api/run-store), `CacheStoreMetrics` in
|
|
19
|
+
[`@smthrs/step-cache`](/api/step-cache), `ArtifactStoreMetrics` in
|
|
20
|
+
[`@smthrs/artifacts`](/api/artifacts), and `DatabaseMetrics` in
|
|
21
|
+
[`@smthrs/database`](/api/database).
|
|
22
|
+
|
|
23
|
+
None of those packages allocates an exporter. Effect's tracer and metric
|
|
24
|
+
registry are collection points; with no exporter installed they collect and
|
|
25
|
+
discard, at a cost close to zero.
|
|
26
|
+
|
|
27
|
+
## Spans Effect names
|
|
28
|
+
|
|
29
|
+
A Smithers package names its own spans for the operation, such as
|
|
30
|
+
`RunStore.claim` or `Journal.emitDurable`. Effect names the spans of the SQL,
|
|
31
|
+
HTTP and RPC clients those packages use:
|
|
32
|
+
|
|
33
|
+
| Span | Name | Kind | What it carries |
|
|
34
|
+
| --------------- | -------------------------------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
35
|
+
| SQL statement | The database system: `sqlite` or `postgresql` | `client` | `db.system.name`, `db.query.text` and `effect.sql.method` |
|
|
36
|
+
| SQL transaction | `sql.transaction` | `internal` | The events `effect.sql.transaction.commit`, `effect.sql.transaction.savepoint` and `effect.sql.transaction.rollback` |
|
|
37
|
+
| HTTP request | The request method, such as `POST` | `client` | `http.request.method`, `url.full`, `url.path`, `url.scheme`, `server.address`, `server.port` and `http.response.status_code` |
|
|
38
|
+
| RPC call | The procedure's tag, such as `Projection.Snapshot` | `client`, `server` | `rpc.system.name` (`effect_rpc`) and `rpc.method` |
|
|
39
|
+
|
|
40
|
+
On an HTTP request span, `server.address` is the host name without the scheme,
|
|
41
|
+
and `server.port` is always present, as the scheme's default when the URL names
|
|
42
|
+
none.
|
|
43
|
+
|
|
44
|
+
An HTTP request span records no request or response header. A host that wants
|
|
45
|
+
them provides `HttpClient.TracerHeaderFilter`. The model, artifact and
|
|
46
|
+
step-cache packages add their credential header names to
|
|
47
|
+
`Headers.CurrentRedactedNames`, so a recorded credential header of theirs reads
|
|
48
|
+
`<redacted>`. Every other recorded header keeps its value, apart from the names
|
|
49
|
+
Effect redacts itself, such as `authorization`, `cookie`, `set-cookie` and
|
|
50
|
+
`x-api-key`.
|
|
51
|
+
|
|
52
|
+
A `4xx` or `5xx` answer ends an HTTP request span as failed, with the status in
|
|
53
|
+
`error.type`. That holds even where the calling package treats the status as an
|
|
54
|
+
ordinary answer: a shared-cache miss is a failed `GET` span with `error.type`
|
|
55
|
+
`404` inside a lookup span that succeeded.
|
|
56
|
+
|
|
57
|
+
## This package is the exporter
|
|
58
|
+
|
|
59
|
+
`Otlp.layerFetch` installs Effect's OTLP logger, metrics exporter, and tracer
|
|
60
|
+
against a collector endpoint, with a service identity filled in. That is the
|
|
61
|
+
whole wiring, and it is why telemetry is additive rather than invasive:
|
|
62
|
+
providing one layer turns on delivery for instrumentation that was already
|
|
63
|
+
there, and removing the line turns it off without touching a flow body.
|
|
64
|
+
|
|
65
|
+
The split also keeps the dependency in one place. Because `Otlp` composes only
|
|
66
|
+
what `effect` already ships, a package that wants a counter takes on no
|
|
67
|
+
OpenTelemetry dependency to get one, and the process pays for an SDK only if a
|
|
68
|
+
host chooses `NodeOtel` or `BrowserOtel`.
|
|
69
|
+
|
|
70
|
+
## The producer owns the meaning, the exporter owns the delivery
|
|
71
|
+
|
|
72
|
+
A metric handle belongs to the package that knows when to advance it. This
|
|
73
|
+
package holds only the four cross-package runtime signals nobody else owns,
|
|
74
|
+
and it holds them so the producers can share one identifier:
|
|
75
|
+
`flows_run_throughput` is updated in [`@smthrs/run-store`](/api/run-store),
|
|
76
|
+
`flows_seat_active` and `flows_quota_park` in [`@smthrs/agent`](/api/agent),
|
|
77
|
+
and `flows_observability_log_dropped` here. Step-cache counters stay in
|
|
78
|
+
[`@smthrs/step-cache`](/api/step-cache); this package does not duplicate them.
|
|
79
|
+
|
|
80
|
+
The consequence for a reader: a metric's name tells you which package to open
|
|
81
|
+
to learn what advances it, and this package tells you only how it leaves the
|
|
82
|
+
process.
|
|
83
|
+
|
|
84
|
+
## Three ways to read one run
|
|
85
|
+
|
|
86
|
+
Export is one read path, not the only one, and the other two need no collector:
|
|
87
|
+
|
|
88
|
+
1. **The OTLP trace.** Every span and series posts to your collector. Filter on
|
|
89
|
+
the `service.name` you passed to the layer.
|
|
90
|
+
2. **The durable journal.** `Journal.entries` reads a run's lifecycle events in
|
|
91
|
+
process, and `JournalLogger` puts the run's log records on that same
|
|
92
|
+
history. See [Forward logs to the run journal](../guides/forward-logs-to-the-journal.md).
|
|
93
|
+
3. **The metric handles.** Effect's `Metric.value` reads a counter in process,
|
|
94
|
+
with no exporter installed at all. See
|
|
95
|
+
[Read the runtime metrics](../guides/read-runtime-metrics.md).
|
|
96
|
+
|
|
97
|
+
The three tell the same story about the same run, which is what makes a
|
|
98
|
+
disagreement between them worth investigating.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "The layer map"
|
|
3
|
+
description: "The five telemetry layer builders this package ships, what each one allocates, and the rule that keeps the root entry point free of Node modules."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 2
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Five builders produce a telemetry layer, and they differ in one thing: how much
|
|
9
|
+
they allocate for you.
|
|
10
|
+
|
|
11
|
+
## The five builders
|
|
12
|
+
|
|
13
|
+
| Builder | Allocates | Reach for it when |
|
|
14
|
+
| ----------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
15
|
+
| `Otlp.layerFetch` | Effect's three OTLP exporters, plus the host's global `fetch` | You have a collector and no other OpenTelemetry requirement. This is the default. |
|
|
16
|
+
| `Otlp.layer` | Effect's three OTLP exporters. You provide the `HttpClient` | You need a specific HTTP client, such as Undici on Node. |
|
|
17
|
+
| `NodeOtel.layerOtel` | The Node OpenTelemetry SDK: three OTLP/HTTP exporters and their processors | Node code that must run through the OpenTelemetry SDK. |
|
|
18
|
+
| `BrowserOtel.layerOtel` | The web OpenTelemetry SDK around processors and readers you construct | Browser code that must run through the OpenTelemetry SDK. |
|
|
19
|
+
| `Otel.layerOtel` | Effect bridges; optional caller factories build providers | The application controls SDK provider construction. |
|
|
20
|
+
|
|
21
|
+
Each has an explicit do-nothing counterpart: `Otlp.layerNoop` and
|
|
22
|
+
`Otel.layerNoop` both provide nothing and export nothing, so wiring code
|
|
23
|
+
switches layers instead of branching around a missing one.
|
|
24
|
+
|
|
25
|
+
## Why `Otlp` is the default
|
|
26
|
+
|
|
27
|
+
`Otlp` composes only `effect/observability/Otlp`, so it adds no
|
|
28
|
+
OpenTelemetry SDK to the process, and it delivers over Effect's `HttpClient`
|
|
29
|
+
rather than a platform transport. That makes it the cheapest wiring and the
|
|
30
|
+
only one that runs unchanged in Node, in Bun, and in a browser.
|
|
31
|
+
|
|
32
|
+
Reach past it when something other than a collector endpoint is in play: an
|
|
33
|
+
existing OpenTelemetry instrumentation you must feed, a vendor exporter that is
|
|
34
|
+
not OTLP/HTTP JSON, or a provider a framework hands you.
|
|
35
|
+
|
|
36
|
+
## Why the root entry point stops at `Otel`
|
|
37
|
+
|
|
38
|
+
The root entry point exports `Otlp`, `Endpoint`, `JournalLogger`, `Logger`,
|
|
39
|
+
`Metric`, `Otel`, and `Resource`. It stops there because those seven resolve
|
|
40
|
+
nothing host-specific.
|
|
41
|
+
|
|
42
|
+
`NodeOtel` does. It reaches `@effect/opentelemetry/NodeSdk` and
|
|
43
|
+
`@opentelemetry/sdk-trace-node`, and the latter pulls
|
|
44
|
+
`@opentelemetry/context-async-hooks`, which imports the bare specifier
|
|
45
|
+
`async_hooks`. A browser bundler cannot resolve that, so re-exporting `NodeOtel`
|
|
46
|
+
from the root would break the root's browser bundle for every consumer,
|
|
47
|
+
including those that never wanted an SDK. `BrowserOtel` is kept beside it for
|
|
48
|
+
symmetry: a module that binds one host belongs on a subpath.
|
|
49
|
+
|
|
50
|
+
Nothing the root entry point reaches resolves a `node:` built-in, as an ESM
|
|
51
|
+
import or as a `require("node:...")` call, so a browser bundle of the root
|
|
52
|
+
carries no host module.
|
|
53
|
+
|
|
54
|
+
## `Resource` sits under all of them
|
|
55
|
+
|
|
56
|
+
Every builder decodes the same `Resource.Configuration`. `Otlp`, `NodeOtel`,
|
|
57
|
+
and `BrowserOtel` attach its attributes to all enabled signals. `Otel.layerOtel`
|
|
58
|
+
passes that validated resource to provider factories and the metric producer;
|
|
59
|
+
factories must use it when constructing tracer and logger providers.
|
|
60
|
+
|
|
61
|
+
Already-created providers retain their own resources. For those providers,
|
|
62
|
+
`Otel.layerOtel`'s resource option sets only the metric resource. Construct
|
|
63
|
+
them with the intended resource before injection to give all three signals the
|
|
64
|
+
same service identity. Spans and log records carry the instrumentation scope
|
|
65
|
+
`effect` with the Effect version, whatever the resource.
|
|
66
|
+
|
|
67
|
+
`Resource.layer` provides the resource on its own, for a composition that
|
|
68
|
+
assembles the rest itself.
|
|
69
|
+
|
|
70
|
+
`Otlp` is the one builder with defaults: `Otlp.defaultServiceName` is `flows`
|
|
71
|
+
and `Otlp.defaultServiceVersion` is this package's release version. Name your
|
|
72
|
+
own service in production, so a collector holding several Smithers processes
|
|
73
|
+
can tell them apart.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Validation at layer acquisition"
|
|
3
|
+
description: "Export failure is absorbed by design, so a misconfigured exporter looks exactly like a working one. Endpoints and resources are therefore decoded when the layer is built, and refused with typed errors."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 3
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
An exporter that cannot deliver must not take the application down with it. A
|
|
9
|
+
collector outage is not an application outage, so Effect's exporter absorbs
|
|
10
|
+
export failure: it retries a transient failure three times, then temporarily
|
|
11
|
+
disables delivery, and the effect that produced the span never learns any of
|
|
12
|
+
it.
|
|
13
|
+
|
|
14
|
+
That is the right behavior, and it creates one hazard. A layer built against
|
|
15
|
+
`""`, `localhost:4318`, or an endpoint with a trailing newline behaves
|
|
16
|
+
identically to a working one: it builds, it runs, it fails nothing, and it
|
|
17
|
+
delivers nothing forever. Nobody notices until an operator goes looking for a
|
|
18
|
+
trace that was never sent.
|
|
19
|
+
|
|
20
|
+
## Acquisition is the only place to report it
|
|
21
|
+
|
|
22
|
+
So both configuration inputs are decoded while the layer is being built, before
|
|
23
|
+
any exporter exists:
|
|
24
|
+
|
|
25
|
+
- The collector endpoint, by `Endpoint.decode`, failing with
|
|
26
|
+
`Endpoint.InvalidExporterEndpoint`.
|
|
27
|
+
- The service identity and resource attributes, by `Resource.decode`, failing
|
|
28
|
+
with `Resource.InvalidResourceConfiguration`.
|
|
29
|
+
|
|
30
|
+
Both are typed failures in the layer's error channel, which means a composition
|
|
31
|
+
sees them at startup, in the place where the value was written, rather than as
|
|
32
|
+
silence in a dashboard weeks later. `Otlp.layer`, `Otlp.layerFetch`, and
|
|
33
|
+
`NodeOtel.layerOtel` all decode their endpoint; every builder decodes its
|
|
34
|
+
resource.
|
|
35
|
+
|
|
36
|
+
## What an endpoint must be
|
|
37
|
+
|
|
38
|
+
An absolute `http://` or `https://` URL, at most 2,048 characters, carrying no
|
|
39
|
+
username, password, query, fragment, backslashes, spaces, or control characters.
|
|
40
|
+
Base paths such as `https://collector.example/tenant/9` are supported.
|
|
41
|
+
|
|
42
|
+
Queries and fragments are refused because exporters append `/v1/<signal>` to
|
|
43
|
+
the base. Appending it after `?tenant=9` or `#notes` would leave the HTTP request
|
|
44
|
+
path unchanged, silently sending telemetry to the wrong route. Use exporter
|
|
45
|
+
headers for authentication, not credentials embedded in the URL.
|
|
46
|
+
|
|
47
|
+
The last clause is the one that surprises people, and it is the whole reason
|
|
48
|
+
`Endpoint` exists rather than a bare `new URL` check. The WHATWG URL parser is a
|
|
49
|
+
repairer, not a validator: it strips leading and trailing spaces and C0
|
|
50
|
+
controls, and removes tab, newline, and carriage return from anywhere in its
|
|
51
|
+
input. So `new URL("http://collector:4318\n")` succeeds, and reports a
|
|
52
|
+
well-formed URL, while the untrimmed original is what a builder would hand its
|
|
53
|
+
exporter. An endpoint read from a config file with a trailing newline, or
|
|
54
|
+
pasted with a leading space, is the most common shape of this mistake, and it
|
|
55
|
+
produces exactly the silent no-delivery the refusal exists to prevent. No legal
|
|
56
|
+
collector endpoint carries one of those characters, so refusing them costs
|
|
57
|
+
nothing.
|
|
58
|
+
|
|
59
|
+
Repeated trailing separators are normalized away instead of refused:
|
|
60
|
+
`http://host//` and `http://host` both post to `http://host/v1/traces`.
|
|
61
|
+
|
|
62
|
+
## What a resource must be
|
|
63
|
+
|
|
64
|
+
`Resource.Configuration` bounds the identity so an accepted value cannot become
|
|
65
|
+
an unencodable payload later:
|
|
66
|
+
|
|
67
|
+
- `serviceName` and `serviceVersion` are non-empty, well formed, and at most
|
|
68
|
+
1,024 UTF-16 code units.
|
|
69
|
+
- At most 256 attributes, with non-empty, well formed keys of at most 1,024
|
|
70
|
+
code units.
|
|
71
|
+
- Attribute values are finite numbers, booleans, strings of at most 65,536 code
|
|
72
|
+
units, or homogeneous arrays of one of those scalar types with at most 256
|
|
73
|
+
elements (`Resource.maximumAttributeArrayLength`).
|
|
74
|
+
- The complete OTLP JSON resource is at most 128 KiB
|
|
75
|
+
(`Resource.maximumResourceBytes`), including identity, SDK-added
|
|
76
|
+
`telemetry.sdk.name`, `telemetry.sdk.language` and `telemetry.sdk.version`,
|
|
77
|
+
keys, values, array wrappers, escaping and UTF-8. SDK fields are reserved even for the default Effect
|
|
78
|
+
exporter. Counting stops as soon as the budget is exceeded;
|
|
79
|
+
the value-free refusal names `attributes`, the measured lower bound and limit.
|
|
80
|
+
Per-field limits alone cannot guarantee this cumulative bound.
|
|
81
|
+
- Resource metadata is explicit. The default OTLP and Node SDK layers isolate
|
|
82
|
+
ambient resource configuration so it cannot enlarge metadata after admission.
|
|
83
|
+
- The 1 MiB transport reserves 8 KiB for the JSON envelope and escaped scope
|
|
84
|
+
name, which in a metrics request repeats the service name, leaving 888 KiB
|
|
85
|
+
(`Otlp.reservedBatchBytes`) for a signal batch. This is
|
|
86
|
+
about 909 bytes per record at the upstream 1,000-record log or span limit,
|
|
87
|
+
enough for ordinary batches; application records can still be too large.
|
|
88
|
+
- NUL and unpaired UTF-16 surrogates are refused anywhere. Valid astral Unicode
|
|
89
|
+
is preserved.
|
|
90
|
+
|
|
91
|
+
An empty `serviceName` is refused rather than defaulted, because anonymous
|
|
92
|
+
telemetry in a shared collector is worse than none.
|
|
93
|
+
|
|
94
|
+
## Refusals never carry the rejected value
|
|
95
|
+
|
|
96
|
+
Both errors report a stable `code`, the `path` of the option the bad value
|
|
97
|
+
arrived on, and a message. Neither retains the value itself: `baseUrl` is the
|
|
98
|
+
field most likely to carry a token in a query string or a credential in its
|
|
99
|
+
userinfo, and an error message is the least controlled surface in a system. The
|
|
100
|
+
`path` is what you need to find the value, and you already have the value.
|
|
101
|
+
|
|
102
|
+
The `path` names the caller's own option, so a refusal from `Otlp` says
|
|
103
|
+
`baseUrl` and one from `NodeOtel` says `endpoint`.
|
|
104
|
+
|
|
105
|
+
For what to do when you see one, see
|
|
106
|
+
[Troubleshooting](../troubleshooting.md).
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Export to an OTLP collector"
|
|
3
|
+
description: "Wire Otlp.layerFetch into a running program: the collector endpoint, the service identity, authentication headers, export cadence, the shutdown flush, and what happens when the collector is down."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`Otlp` posts logs, metrics, and traces to an OTLP/HTTP collector as JSON. This
|
|
9
|
+
guide covers the options you set once at startup and the behavior you should
|
|
10
|
+
expect from them afterwards.
|
|
11
|
+
|
|
12
|
+
## Provide the layer
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import * as Otlp from "@smthrs/observability/Otlp"
|
|
16
|
+
import * as Effect from "effect/Effect"
|
|
17
|
+
|
|
18
|
+
const telemetry = Otlp.layerFetch({
|
|
19
|
+
baseUrl: "http://localhost:4318",
|
|
20
|
+
serviceName: "deploy-status"
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// `program` is your application effect, unchanged from its non-telemetry form.
|
|
24
|
+
const outcome = program.pipe(Effect.provide(telemetry), Effect.scoped)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The layer is scoped: give it a lifetime with `Effect.scoped`, or build it as
|
|
28
|
+
part of a runtime that owns a scope. Signals post below `baseUrl` at
|
|
29
|
+
`/v1/logs`, `/v1/metrics`, and `/v1/traces`, so a base URL with a path prefix
|
|
30
|
+
is honored: `http://collector:4318/tenant/9` posts to
|
|
31
|
+
`http://collector:4318/tenant/9/v1/traces`.
|
|
32
|
+
|
|
33
|
+
`Otlp.layer` is the same wiring without the `fetch` binding. Use it when the
|
|
34
|
+
host must supply its own HTTP client:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import * as NodeHost from "@smthrs/platform-node/NodeHost"
|
|
38
|
+
import * as Layer from "effect/Layer"
|
|
39
|
+
|
|
40
|
+
const telemetry = Otlp.layer({ baseUrl: "http://localhost:4318" }).pipe(
|
|
41
|
+
Layer.provide(NodeHost.NodeHttpClient.layerUndici)
|
|
42
|
+
)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Name the service
|
|
46
|
+
|
|
47
|
+
`serviceName` and `serviceVersion` become the `service.name` and
|
|
48
|
+
`service.version` resource attributes on every exported signal, and they are
|
|
49
|
+
how a collector holding several processes tells them apart. Omitted, they fall
|
|
50
|
+
back to `Otlp.defaultServiceName` (`flows`) and `Otlp.defaultServiceVersion`
|
|
51
|
+
(this package's release version), which is a reasonable default for a Smithers
|
|
52
|
+
CLI process and a poor one for your application.
|
|
53
|
+
|
|
54
|
+
Add deployment facts as `attributes`:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
const telemetry = Otlp.layerFetch({
|
|
58
|
+
baseUrl: "https://otlp.example.com",
|
|
59
|
+
serviceName: "deploy-status",
|
|
60
|
+
serviceVersion: "2.4.1",
|
|
61
|
+
attributes: {
|
|
62
|
+
"deployment.environment.name": "production",
|
|
63
|
+
"service.instance.id": process.env.HOSTNAME ?? "local"
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Attribute values are strings, finite numbers, booleans, or homogeneous arrays
|
|
69
|
+
of those. The full bounds are in
|
|
70
|
+
[Validation at layer acquisition](../concepts/validated-acquisition.md).
|
|
71
|
+
|
|
72
|
+
## Authenticate
|
|
73
|
+
|
|
74
|
+
`headers` is sent with every export request, which is where a vendor token
|
|
75
|
+
goes:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const telemetry = Otlp.layerFetch({
|
|
79
|
+
baseUrl: "https://otlp.example.com",
|
|
80
|
+
serviceName: "deploy-status",
|
|
81
|
+
headers: { authorization: "Bearer YOUR_TOKEN" }
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Read the token from the environment or your secret store. A credential in the
|
|
86
|
+
URL is refused: an endpoint carrying userinfo fails layer acquisition. A
|
|
87
|
+
credential header (`authorization`, `x-api-key`, `x-honeycomb-team`, and
|
|
88
|
+
similar names) over plaintext `http://` is refused too, unless the collector is
|
|
89
|
+
on `localhost`, `127.0.0.0/8`, or `[::1]`. Non-credential headers such as a
|
|
90
|
+
tenant id work on any endpoint. The check reads header names only, so use
|
|
91
|
+
`https://` for every remote collector.
|
|
92
|
+
|
|
93
|
+
Fetch redirects are refused, including same-origin redirects. Configure the
|
|
94
|
+
collector's final URL. Other HTTP transports must refuse redirects themselves.
|
|
95
|
+
For fetch options such as `credentials: "omit"`, provide
|
|
96
|
+
`FetchHttpClient.RequestInit` around the whole exporting effect:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient"
|
|
100
|
+
|
|
101
|
+
const outcome = program.pipe(
|
|
102
|
+
Effect.provide(telemetry),
|
|
103
|
+
Effect.provideService(FetchHttpClient.RequestInit, { credentials: "omit" }),
|
|
104
|
+
Effect.scoped
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Options supplied only to the inner HTTP-client layer are replaced by the
|
|
109
|
+
redirect policy. Ambient options are retained except `redirect`, which is
|
|
110
|
+
always `"manual"`. Redirect responses fail export through the existing failure
|
|
111
|
+
handling below; they never forward credentials or signal bodies.
|
|
112
|
+
|
|
113
|
+
## Control the cadence and the flush
|
|
114
|
+
|
|
115
|
+
`exportInterval` sets how often all three signals batch and post. Omitted, each
|
|
116
|
+
signal keeps Effect's own default. `shutdownTimeout` bounds the final flush
|
|
117
|
+
when the layer's scope closes.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const telemetry = Otlp.layerFetch({
|
|
121
|
+
baseUrl: "http://localhost:4318",
|
|
122
|
+
serviceName: "deploy-status",
|
|
123
|
+
exportInterval: "10 seconds",
|
|
124
|
+
shutdownTimeout: "5 seconds"
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Closing the scope is the deterministic flush. A short program may deliver
|
|
129
|
+
nothing on the interval and everything at shutdown, so read what a collector
|
|
130
|
+
received only after the scope has closed.
|
|
131
|
+
|
|
132
|
+
## Turn export off explicitly
|
|
133
|
+
|
|
134
|
+
`Otlp.layerNoop` provides nothing and exports nothing. It exists so a host that
|
|
135
|
+
has no collector, or a browser build that has not opted in, switches layers
|
|
136
|
+
rather than branching around a missing provide:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
const telemetry = collectorUrl === undefined
|
|
140
|
+
? Otlp.layerNoop
|
|
141
|
+
: Otlp.layerFetch({ baseUrl: collectorUrl, serviceName: "deploy-status" })
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## What the collector receives
|
|
145
|
+
|
|
146
|
+
Every request is OTLP/HTTP JSON. Its `user-agent` is
|
|
147
|
+
`OTel-OTLP-Exporter-JavaScript-Effect-OtlpTracer/` and the Effect version, with
|
|
148
|
+
`OtlpLogger` or `OtlpMetrics` for the other two signals, after any `user-agent`
|
|
149
|
+
you set in `headers`.
|
|
150
|
+
|
|
151
|
+
| Part | What it carries |
|
|
152
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
153
|
+
| Resource | `telemetry.sdk.name` (`effect`), `telemetry.sdk.language` (`nodejs` or `webjs`) and `telemetry.sdk.version` (the Effect version), then your `attributes`, `service.name` and `service.version`. |
|
|
154
|
+
| Scope | Spans and log records name their scope `effect`, with the Effect version. Metrics name their scope for your service. |
|
|
155
|
+
| Spans | Status `1` on success. Status `2` on failure, with the first error's message and one `exception` event per error. Status `0` and the attribute `effect.fiber.interrupted` on interruption. Failure text and string attributes are redacted before they leave. |
|
|
156
|
+
| Log records | Your annotations as attributes, plus `effect.fiberId` and, for each log span, `effect.log_span.<label>` holding the elapsed milliseconds as a number. A record logged with a cause adds `exception.type`, `exception.message` and `exception.stacktrace`. |
|
|
157
|
+
| Metrics | Counters, gauges and histograms under the names the producing package declares. A timer's unit is `ms`. A histogram lists every boundary it declares in `explicitBounds` and counts values above the last one in a final bucket. |
|
|
158
|
+
|
|
159
|
+
The names of the spans themselves are in
|
|
160
|
+
[Instrumentation and export](../concepts/instrumentation-and-export.md#spans-effect-names).
|
|
161
|
+
|
|
162
|
+
## What happens when the collector is down
|
|
163
|
+
|
|
164
|
+
Export failure never fails your program, and it never surfaces as a rejected
|
|
165
|
+
promise. Effect's exporter retries a transient failure three times, honoring a
|
|
166
|
+
`retry-after` response header on any retried status when one is present, then
|
|
167
|
+
disables that exporter for 60 seconds and logs a `Debug` record saying so.
|
|
168
|
+
Spans and records produced inside that window are dropped, and delivery resumes
|
|
169
|
+
afterwards.
|
|
170
|
+
|
|
171
|
+
The exporter reads a response's status and `retry-after` header and nothing
|
|
172
|
+
else. Each exchange ends when the status arrives, so a collector that accepts a
|
|
173
|
+
batch and never finishes its answer does not hold up the next one.
|
|
174
|
+
|
|
175
|
+
Two consequences worth planning for:
|
|
176
|
+
|
|
177
|
+
- A dead collector is invisible at `Info`. Run at `Debug` while you are
|
|
178
|
+
bringing an exporter up, or watch the collector side.
|
|
179
|
+
- A configuration mistake and a collector outage look the same after
|
|
180
|
+
acquisition. That is why the endpoint is decoded before any exporter exists;
|
|
181
|
+
see [Troubleshooting](../troubleshooting.md) when nothing arrives.
|
|
182
|
+
|
|
183
|
+
## Next steps
|
|
184
|
+
|
|
185
|
+
- [Test telemetry without a collector](./testing.md): assert on what would have
|
|
186
|
+
been posted.
|
|
187
|
+
- [Wire an OpenTelemetry SDK](./wire-an-opentelemetry-sdk.md): when a collector
|
|
188
|
+
endpoint is not enough.
|
|
189
|
+
- [Read the runtime metrics](./read-runtime-metrics.md): what the exported
|
|
190
|
+
series mean.
|