autotel 4.3.0 → 5.0.0
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/README.md +125 -103
- package/dist/analysis.cjs +87 -0
- package/dist/analysis.cjs.map +1 -0
- package/dist/analysis.d.cts +87 -0
- package/dist/analysis.d.cts.map +1 -0
- package/dist/analysis.d.ts +87 -0
- package/dist/analysis.d.ts.map +1 -0
- package/dist/analysis.js +85 -0
- package/dist/analysis.js.map +1 -0
- package/dist/{attribute-redacting-processor-DtTS9xxh.d.ts → attribute-redacting-processor-Pk7lAzWd.d.cts} +13 -8
- package/dist/attribute-redacting-processor-Pk7lAzWd.d.cts.map +1 -0
- package/dist/{attribute-redacting-processor-DtTS9xxh.d.cts → attribute-redacting-processor-Pk7lAzWd.d.ts} +13 -8
- package/dist/attribute-redacting-processor-Pk7lAzWd.d.ts.map +1 -0
- package/dist/attribute-redacting-processor.cjs +4 -4
- package/dist/attribute-redacting-processor.cjs.map +1 -1
- package/dist/attribute-redacting-processor.d.cts +1 -1
- package/dist/attribute-redacting-processor.d.ts +1 -1
- package/dist/attribute-redacting-processor.js +4 -4
- package/dist/attribute-redacting-processor.js.map +1 -1
- package/dist/attributes.d.cts +1 -1
- package/dist/attributes.d.ts +1 -1
- package/dist/auto.cjs +1 -1
- package/dist/auto.cjs.map +1 -1
- package/dist/auto.d.cts +1 -1
- package/dist/auto.d.ts +1 -1
- package/dist/auto.js +1 -1
- package/dist/auto.js.map +1 -1
- package/dist/business-baggage.d.cts +2 -3
- package/dist/business-baggage.d.cts.map +1 -1
- package/dist/business-baggage.d.ts +2 -3
- package/dist/business-baggage.d.ts.map +1 -1
- package/dist/{canonical-log-line-processor-xvjMgtpF.d.cts → canonical-log-line-processor-B4WgG-VS.d.cts} +2 -3
- package/dist/canonical-log-line-processor-B4WgG-VS.d.cts.map +1 -0
- package/dist/{canonical-log-line-processor-BcRuAdRk.d.ts → canonical-log-line-processor-CL_J7gb5.d.ts} +2 -3
- package/dist/canonical-log-line-processor-CL_J7gb5.d.ts.map +1 -0
- package/dist/{canonical-log-line-processor-CcrDi6TO.cjs → canonical-log-line-processor-DOjb6Kxy.cjs} +5 -5
- package/dist/canonical-log-line-processor-DOjb6Kxy.cjs.map +1 -0
- package/dist/{canonical-log-line-processor-FLezvFCB.js → canonical-log-line-processor-mKABvGP0.js} +5 -5
- package/dist/canonical-log-line-processor-mKABvGP0.js.map +1 -0
- package/dist/config.d.cts +12 -7
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.ts +12 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/correlation-id.cjs +1 -1
- package/dist/correlation-id.d.cts +0 -1
- package/dist/correlation-id.d.cts.map +1 -1
- package/dist/correlation-id.d.ts +0 -1
- package/dist/correlation-id.d.ts.map +1 -1
- package/dist/correlation-id.js +1 -1
- package/dist/db.d.cts.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/decorators.cjs +1 -1
- package/dist/decorators.cjs.map +1 -1
- package/dist/decorators.d.cts +1 -2
- package/dist/decorators.d.cts.map +1 -1
- package/dist/decorators.d.ts +1 -2
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +1 -1
- package/dist/decorators.js.map +1 -1
- package/dist/{define-event-CreknLm3.d.ts → define-event-B2z1SBe7.d.ts} +2 -3
- package/dist/define-event-B2z1SBe7.d.ts.map +1 -0
- package/dist/{define-event-HZRizPwz.d.cts → define-event-CGG048HE.d.cts} +2 -3
- package/dist/define-event-CGG048HE.d.cts.map +1 -0
- package/dist/diagnostics.cjs +10 -1
- package/dist/diagnostics.cjs.map +1 -1
- package/dist/diagnostics.d.cts +0 -1
- package/dist/diagnostics.d.cts.map +1 -1
- package/dist/diagnostics.d.ts +0 -1
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +10 -1
- package/dist/diagnostics.js.map +1 -1
- package/dist/drain-pipeline.d.cts +12 -5
- package/dist/drain-pipeline.d.cts.map +1 -1
- package/dist/drain-pipeline.d.ts +12 -5
- package/dist/drain-pipeline.d.ts.map +1 -1
- package/dist/enrichers.d.cts.map +1 -1
- package/dist/enrichers.d.ts.map +1 -1
- package/dist/{event-rzA1X5h3.cjs → event-CwIpFdoY.cjs} +3 -3
- package/dist/event-CwIpFdoY.cjs.map +1 -0
- package/dist/{event-BEm5IJ8U.js → event-pLMF5b3d.js} +4 -4
- package/dist/event-pLMF5b3d.js.map +1 -0
- package/dist/{event-subscriber-D1XLkPzi.d.ts → event-subscriber-CWh8sTGh.d.cts} +2 -2
- package/dist/event-subscriber-CWh8sTGh.d.cts.map +1 -0
- package/dist/{event-subscriber-D1XLkPzi.d.cts → event-subscriber-CWh8sTGh.d.ts} +2 -2
- package/dist/event-subscriber-CWh8sTGh.d.ts.map +1 -0
- package/dist/event-subscriber.d.cts +1 -1
- package/dist/event-subscriber.d.ts +1 -1
- package/dist/{event-testing-CfFs3to2.d.ts → event-testing-CA2mIx1E.d.ts} +2 -3
- package/dist/event-testing-CA2mIx1E.d.ts.map +1 -0
- package/dist/{event-testing-BqRnI0z4.d.cts → event-testing-D0qWfqAy.d.cts} +2 -3
- package/dist/event-testing-D0qWfqAy.d.cts.map +1 -0
- package/dist/event-testing.d.cts +1 -1
- package/dist/event-testing.d.ts +1 -1
- package/dist/event.cjs +1 -1
- package/dist/event.d.cts +3 -4
- package/dist/event.d.cts.map +1 -1
- package/dist/event.d.ts +3 -4
- package/dist/event.d.ts.map +1 -1
- package/dist/event.js +1 -1
- package/dist/exporters.d.cts +0 -4
- package/dist/exporters.d.cts.map +1 -1
- package/dist/exporters.d.ts +0 -4
- package/dist/exporters.d.ts.map +1 -1
- package/dist/{filtering-span-processor-B8R8B7Uk.d.ts → filtering-span-processor-BpDagWNa.d.cts} +1 -2
- package/dist/filtering-span-processor-BpDagWNa.d.cts.map +1 -0
- package/dist/{filtering-span-processor-B8R8B7Uk.d.cts → filtering-span-processor-BpDagWNa.d.ts} +1 -2
- package/dist/filtering-span-processor-BpDagWNa.d.ts.map +1 -0
- package/dist/filtering-span-processor.d.cts +1 -1
- package/dist/filtering-span-processor.d.ts +1 -1
- package/dist/functional-Bit6noRu.js +840 -0
- package/dist/functional-Bit6noRu.js.map +1 -0
- package/dist/functional-Cj7PSItS.cjs +890 -0
- package/dist/functional-Cj7PSItS.cjs.map +1 -0
- package/dist/functional.cjs +2 -2
- package/dist/functional.d.cts +79 -130
- package/dist/functional.d.cts.map +1 -1
- package/dist/functional.d.ts +79 -130
- package/dist/functional.d.ts.map +1 -1
- package/dist/functional.js +2 -2
- package/dist/http.cjs +5 -5
- package/dist/http.cjs.map +1 -1
- package/dist/http.d.cts +4 -5
- package/dist/http.d.cts.map +1 -1
- package/dist/http.d.ts +4 -5
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +5 -5
- package/dist/http.js.map +1 -1
- package/dist/{index-eKuioqT1.d.cts → index-BPcxVucm.d.cts} +2 -3
- package/dist/index-BPcxVucm.d.cts.map +1 -0
- package/dist/{index-Ck06vlW2.d.ts → index-DolOVX6F.d.ts} +2 -3
- package/dist/index-DolOVX6F.d.ts.map +1 -0
- package/dist/index.cjs +7 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +14 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -8
- package/dist/index.js.map +1 -1
- package/dist/{init-BxJEJ9Tn.cjs → init-B2uvZReD.cjs} +19 -10
- package/dist/init-B2uvZReD.cjs.map +1 -0
- package/dist/{init-B7u-DjxM.d.ts → init-CTyqG9qR.d.ts} +24 -17
- package/dist/init-CTyqG9qR.d.ts.map +1 -0
- package/dist/{init-BvBB45-T.js → init-CdEWjhvl.js} +20 -11
- package/dist/init-CdEWjhvl.js.map +1 -0
- package/dist/{init-DSrRmVnz.d.cts → init-a4yPDYqC.d.cts} +24 -17
- package/dist/init-a4yPDYqC.d.cts.map +1 -0
- package/dist/instrumentation.cjs +7 -13
- package/dist/instrumentation.cjs.map +1 -1
- package/dist/instrumentation.d.cts +0 -1
- package/dist/instrumentation.d.cts.map +1 -1
- package/dist/instrumentation.d.ts +0 -1
- package/dist/instrumentation.d.ts.map +1 -1
- package/dist/instrumentation.js +8 -14
- package/dist/instrumentation.js.map +1 -1
- package/dist/{logger-BauSUhUv.d.ts → logger-CN4xpzMd.d.cts} +1 -2
- package/dist/logger-CN4xpzMd.d.cts.map +1 -0
- package/dist/{logger-BauSUhUv.d.cts → logger-CN4xpzMd.d.ts} +1 -2
- package/dist/logger-CN4xpzMd.d.ts.map +1 -0
- package/dist/logger-D3Ej3DII.js.map +1 -1
- package/dist/logger-thMPLpOG.cjs.map +1 -1
- package/dist/logger.d.cts +1 -1
- package/dist/logger.d.ts +1 -1
- package/dist/messaging-adapters.cjs.map +1 -1
- package/dist/messaging-adapters.d.cts +0 -1
- package/dist/messaging-adapters.d.cts.map +1 -1
- package/dist/messaging-adapters.d.ts +0 -1
- package/dist/messaging-adapters.d.ts.map +1 -1
- package/dist/messaging-adapters.js.map +1 -1
- package/dist/messaging-testing.d.cts +0 -1
- package/dist/messaging-testing.d.cts.map +1 -1
- package/dist/messaging-testing.d.ts +0 -1
- package/dist/messaging-testing.d.ts.map +1 -1
- package/dist/messaging.cjs +27 -10
- package/dist/messaging.cjs.map +1 -1
- package/dist/messaging.d.cts +6 -7
- package/dist/messaging.d.cts.map +1 -1
- package/dist/messaging.d.ts +6 -7
- package/dist/messaging.d.ts.map +1 -1
- package/dist/messaging.js +27 -10
- package/dist/messaging.js.map +1 -1
- package/dist/metric-helpers.d.cts +0 -1
- package/dist/metric-helpers.d.cts.map +1 -1
- package/dist/metric-helpers.d.ts +0 -1
- package/dist/metric-helpers.d.ts.map +1 -1
- package/dist/{metric-testing-DXdK3-Q3.d.ts → metric-testing-CWm6UhaR.d.ts} +2 -3
- package/dist/metric-testing-CWm6UhaR.d.ts.map +1 -0
- package/dist/{metric-testing-MxvzChDp.d.cts → metric-testing-CpvP3ZIa.d.cts} +2 -3
- package/dist/metric-testing-CpvP3ZIa.d.cts.map +1 -0
- package/dist/metric-testing.d.cts +1 -1
- package/dist/metric-testing.d.ts +1 -1
- package/dist/metric.d.cts +3 -4
- package/dist/metric.d.cts.map +1 -1
- package/dist/metric.d.ts +3 -4
- package/dist/metric.d.ts.map +1 -1
- package/dist/parse-error.d.cts.map +1 -1
- package/dist/parse-error.d.ts.map +1 -1
- package/dist/processors.cjs +1 -1
- package/dist/processors.d.cts +1 -1
- package/dist/processors.d.ts +1 -1
- package/dist/processors.js +1 -1
- package/dist/register.d.cts +1 -1
- package/dist/register.d.ts +1 -1
- package/dist/{sampling-DfYhDJij.d.cts → sampling-BR9fkSwx.d.cts} +127 -10
- package/dist/sampling-BR9fkSwx.d.cts.map +1 -0
- package/dist/{sampling-CR0Va1VB.d.ts → sampling-CP3e7-Yr.d.ts} +127 -10
- package/dist/sampling-CP3e7-Yr.d.ts.map +1 -0
- package/dist/sampling.cjs +160 -12
- package/dist/sampling.cjs.map +1 -1
- package/dist/sampling.d.cts +2 -2
- package/dist/sampling.d.ts +2 -2
- package/dist/sampling.js +157 -13
- package/dist/sampling.js.map +1 -1
- package/dist/security-schema.d.cts +9 -4
- package/dist/security-schema.d.cts.map +1 -1
- package/dist/security-schema.d.ts +9 -4
- package/dist/security-schema.d.ts.map +1 -1
- package/dist/semantic-conventions-FhSxv-bK.d.cts.map +1 -1
- package/dist/semantic-conventions-FhSxv-bK.d.ts.map +1 -1
- package/dist/semantic-conventions.cjs.map +1 -1
- package/dist/semantic-conventions.js.map +1 -1
- package/dist/semantic-helpers.cjs +85 -304
- package/dist/semantic-helpers.cjs.map +1 -1
- package/dist/semantic-helpers.d.cts +21 -12
- package/dist/semantic-helpers.d.cts.map +1 -1
- package/dist/semantic-helpers.d.ts +21 -12
- package/dist/semantic-helpers.d.ts.map +1 -1
- package/dist/semantic-helpers.js +85 -304
- package/dist/semantic-helpers.js.map +1 -1
- package/dist/slo.cjs +225 -0
- package/dist/slo.cjs.map +1 -0
- package/dist/slo.d.cts +97 -0
- package/dist/slo.d.cts.map +1 -0
- package/dist/slo.d.ts +97 -0
- package/dist/slo.d.ts.map +1 -0
- package/dist/slo.js +223 -0
- package/dist/slo.js.map +1 -0
- package/dist/{span-name-normalizer-8ZOGJuwv.d.ts → span-name-normalizer-CN1-8C76.d.cts} +1 -2
- package/dist/span-name-normalizer-CN1-8C76.d.cts.map +1 -0
- package/dist/{span-name-normalizer-8ZOGJuwv.d.cts → span-name-normalizer-CN1-8C76.d.ts} +1 -2
- package/dist/span-name-normalizer-CN1-8C76.d.ts.map +1 -0
- package/dist/span-name-normalizer.cjs.map +1 -1
- package/dist/span-name-normalizer.d.cts +1 -1
- package/dist/span-name-normalizer.d.ts +1 -1
- package/dist/span-name-normalizer.js.map +1 -1
- package/dist/tail-sampling-processor.d.cts +0 -1
- package/dist/tail-sampling-processor.d.cts.map +1 -1
- package/dist/tail-sampling-processor.d.ts +0 -1
- package/dist/tail-sampling-processor.d.ts.map +1 -1
- package/dist/test-span-collector.cjs.map +1 -1
- package/dist/test-span-collector.d.cts +0 -1
- package/dist/test-span-collector.d.cts.map +1 -1
- package/dist/test-span-collector.d.ts +0 -1
- package/dist/test-span-collector.d.ts.map +1 -1
- package/dist/test-span-collector.js.map +1 -1
- package/dist/testing.cjs +76 -11
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +30 -5
- package/dist/testing.d.cts.map +1 -1
- package/dist/testing.d.ts +30 -5
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +73 -12
- package/dist/testing.js.map +1 -1
- package/dist/{trace-context-Cijqoi6e.d.ts → trace-context-IuyoPyNq.d.cts} +9 -9
- package/dist/trace-context-IuyoPyNq.d.cts.map +1 -0
- package/dist/{trace-context-Cijqoi6e.d.cts → trace-context-IuyoPyNq.d.ts} +9 -9
- package/dist/trace-context-IuyoPyNq.d.ts.map +1 -0
- package/dist/trace-factory-validation-BjVAinz6.js +13 -0
- package/dist/trace-factory-validation-BjVAinz6.js.map +1 -0
- package/dist/trace-factory-validation-Dc8epn87.cjs +19 -0
- package/dist/trace-factory-validation-Dc8epn87.cjs.map +1 -0
- package/dist/trace-helpers.cjs +7 -7
- package/dist/trace-helpers.cjs.map +1 -1
- package/dist/trace-helpers.d.cts +6 -7
- package/dist/trace-helpers.d.cts.map +1 -1
- package/dist/trace-helpers.d.ts +6 -7
- package/dist/trace-helpers.d.ts.map +1 -1
- package/dist/trace-helpers.js +7 -7
- package/dist/trace-helpers.js.map +1 -1
- package/dist/tracer-provider.d.cts +0 -1
- package/dist/tracer-provider.d.cts.map +1 -1
- package/dist/tracer-provider.d.ts +0 -1
- package/dist/tracer-provider.d.ts.map +1 -1
- package/dist/{track-D7O7oIZa.js → track-BBcxEJEC.js} +7 -12
- package/dist/track-BBcxEJEC.js.map +1 -0
- package/dist/{track-eovhCJ-I.cjs → track-BI6dmZ2X.cjs} +6 -17
- package/dist/track-BI6dmZ2X.cjs.map +1 -0
- package/dist/validate.cjs.map +1 -1
- package/dist/validate.d.cts +1 -2
- package/dist/validate.d.cts.map +1 -1
- package/dist/validate.d.ts +1 -2
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js.map +1 -1
- package/dist/validation-attributes.d.cts +17 -8
- package/dist/validation-attributes.d.cts.map +1 -1
- package/dist/validation-attributes.d.ts +17 -8
- package/dist/validation-attributes.d.ts.map +1 -1
- package/dist/webhook.cjs +5 -4
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.d.cts +4 -4
- package/dist/webhook.d.cts.map +1 -1
- package/dist/webhook.d.ts +4 -4
- package/dist/webhook.d.ts.map +1 -1
- package/dist/webhook.js +5 -4
- package/dist/webhook.js.map +1 -1
- package/dist/workflow-distributed.cjs +5 -5
- package/dist/workflow-distributed.cjs.map +1 -1
- package/dist/workflow-distributed.d.cts +25 -15
- package/dist/workflow-distributed.d.cts.map +1 -1
- package/dist/workflow-distributed.d.ts +25 -15
- package/dist/workflow-distributed.d.ts.map +1 -1
- package/dist/workflow-distributed.js +5 -5
- package/dist/workflow-distributed.js.map +1 -1
- package/dist/workflow.cjs +24 -30
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +11 -6
- package/dist/workflow.d.cts.map +1 -1
- package/dist/workflow.d.ts +11 -6
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +24 -30
- package/dist/workflow.js.map +1 -1
- package/dist/yaml-config.d.cts +2 -3
- package/dist/yaml-config.d.cts.map +1 -1
- package/dist/yaml-config.d.ts +2 -3
- package/dist/yaml-config.d.ts.map +1 -1
- package/package.json +23 -14
- package/skills/analyze-traces/SKILL.md +42 -13
- package/skills/autotel-core/SKILL.md +24 -17
- package/skills/autotel-events/SKILL.md +1 -1
- package/skills/autotel-frameworks/SKILL.md +41 -6
- package/skills/autotel-instrumentation/SKILL.md +14 -9
- package/skills/autotel-request-logging/SKILL.md +19 -14
- package/skills/autotel-structured-errors/SKILL.md +2 -2
- package/skills/build-audit-trails/SKILL.md +11 -11
- package/skills/build-audit-trails/references/audit-queries.md +3 -3
- package/skills/debug-missing-spans/SKILL.md +12 -12
- package/skills/migrate-to-autotel/SKILL.md +20 -20
- package/skills/review-otel-patterns/SKILL.md +44 -42
- package/skills/review-otel-patterns/references/code-review.md +4 -4
- package/skills/review-otel-patterns/references/processor-pipeline.md +3 -3
- package/skills/review-otel-patterns/references/structured-errors.md +1 -1
- package/skills/review-otel-patterns/references/wide-spans.md +2 -2
- package/skills/tune-sampling/SKILL.md +91 -16
- package/dist/attribute-redacting-processor-DtTS9xxh.d.cts.map +0 -1
- package/dist/attribute-redacting-processor-DtTS9xxh.d.ts.map +0 -1
- package/dist/canonical-log-line-processor-BcRuAdRk.d.ts.map +0 -1
- package/dist/canonical-log-line-processor-CcrDi6TO.cjs.map +0 -1
- package/dist/canonical-log-line-processor-FLezvFCB.js.map +0 -1
- package/dist/canonical-log-line-processor-xvjMgtpF.d.cts.map +0 -1
- package/dist/define-event-CreknLm3.d.ts.map +0 -1
- package/dist/define-event-HZRizPwz.d.cts.map +0 -1
- package/dist/event-BEm5IJ8U.js.map +0 -1
- package/dist/event-rzA1X5h3.cjs.map +0 -1
- package/dist/event-subscriber-D1XLkPzi.d.cts.map +0 -1
- package/dist/event-subscriber-D1XLkPzi.d.ts.map +0 -1
- package/dist/event-testing-BqRnI0z4.d.cts.map +0 -1
- package/dist/event-testing-CfFs3to2.d.ts.map +0 -1
- package/dist/filtering-span-processor-B8R8B7Uk.d.cts.map +0 -1
- package/dist/filtering-span-processor-B8R8B7Uk.d.ts.map +0 -1
- package/dist/functional-CwsPyc4l.cjs +0 -1298
- package/dist/functional-CwsPyc4l.cjs.map +0 -1
- package/dist/functional-dAYhXQPA.js +0 -1248
- package/dist/functional-dAYhXQPA.js.map +0 -1
- package/dist/index-Ck06vlW2.d.ts.map +0 -1
- package/dist/index-eKuioqT1.d.cts.map +0 -1
- package/dist/init-B7u-DjxM.d.ts.map +0 -1
- package/dist/init-BvBB45-T.js.map +0 -1
- package/dist/init-BxJEJ9Tn.cjs.map +0 -1
- package/dist/init-DSrRmVnz.d.cts.map +0 -1
- package/dist/logger-BauSUhUv.d.cts.map +0 -1
- package/dist/logger-BauSUhUv.d.ts.map +0 -1
- package/dist/metric-testing-DXdK3-Q3.d.ts.map +0 -1
- package/dist/metric-testing-MxvzChDp.d.cts.map +0 -1
- package/dist/sampling-CR0Va1VB.d.ts.map +0 -1
- package/dist/sampling-DfYhDJij.d.cts.map +0 -1
- package/dist/span-name-normalizer-8ZOGJuwv.d.cts.map +0 -1
- package/dist/span-name-normalizer-8ZOGJuwv.d.ts.map +0 -1
- package/dist/trace-context-Cijqoi6e.d.cts.map +0 -1
- package/dist/trace-context-Cijqoi6e.d.ts.map +0 -1
- package/dist/track-D7O7oIZa.js.map +0 -1
- package/dist/track-eovhCJ-I.cjs.map +0 -1
|
@@ -12,7 +12,7 @@ license: MIT
|
|
|
12
12
|
|
|
13
13
|
# Migrate to autotel
|
|
14
14
|
|
|
15
|
-
Replacing tracing in a live service is risky
|
|
15
|
+
Replacing tracing in a live service is risky. You can lose data, change span shapes, or break dashboards your on-call team relies on. This skill covers the safe paths from each major source, what to change in your code, and how to verify the cutover before turning the old stack off.
|
|
16
16
|
|
|
17
17
|
## Choose your starting point
|
|
18
18
|
|
|
@@ -34,11 +34,11 @@ Replacing tracing in a live service is risky — you can lose data, change span
|
|
|
34
34
|
4. **Disable the old stack.** Remove old SDK imports + processors; redeploy.
|
|
35
35
|
5. **Decommission.** Remove old packages from `package.json` and lock files; archive old dashboards.
|
|
36
36
|
|
|
37
|
-
Don't compress this into a single PR. The riskiest step is "disable old stack"
|
|
37
|
+
Don't compress this into a single PR. The riskiest step is "disable old stack". Keep it last.
|
|
38
38
|
|
|
39
39
|
## From raw `@opentelemetry/sdk-node`
|
|
40
40
|
|
|
41
|
-
The smoothest migration. autotel layers on top of OTel
|
|
41
|
+
The smoothest migration. autotel layers on top of OTel. Your span attributes, propagators, and exporters can stay.
|
|
42
42
|
|
|
43
43
|
### Drop-in init
|
|
44
44
|
|
|
@@ -76,15 +76,15 @@ init({
|
|
|
76
76
|
|
|
77
77
|
### What you gain immediately
|
|
78
78
|
|
|
79
|
-
- `useLogger().set({ … })` flattens onto the active span
|
|
80
|
-
- `attributeRedactor: 'default'
|
|
79
|
+
- `useLogger().set({ … })` flattens onto the active span: no more `span.setAttribute('user.id', id)` boilerplate.
|
|
80
|
+
- `attributeRedactor: 'default'`: PII masking for free in production.
|
|
81
81
|
- `destinations: [...]` for straightforward OTLP multi-backend fan-out.
|
|
82
82
|
- Cloudflare Workers + Edge support out of the box (`defineWorkerFetch`).
|
|
83
83
|
|
|
84
84
|
### What stays the same
|
|
85
85
|
|
|
86
86
|
- Your propagator (`W3CTraceContextPropagator` is the default).
|
|
87
|
-
- Your exporters
|
|
87
|
+
- Your exporters: pass them via `spanProcessors` if you want to keep custom ones.
|
|
88
88
|
- Your resource attributes.
|
|
89
89
|
|
|
90
90
|
## From Sentry performance tracing
|
|
@@ -148,7 +148,7 @@ Datadog APM uses its own format and proprietary tracer. The migration path is OT
|
|
|
148
148
|
|
|
149
149
|
### Step 1: Stop importing `dd-trace`
|
|
150
150
|
|
|
151
|
-
`dd-trace` patches every supported library on import
|
|
151
|
+
`dd-trace` patches every supported library on import. Keeping it in the bundle while autotel runs causes double-instrumentation. Remove `import 'dd-trace'` (or the `--require dd-trace/init` arg).
|
|
152
152
|
|
|
153
153
|
### Step 2: Point autotel at Datadog OTLP intake
|
|
154
154
|
|
|
@@ -166,7 +166,7 @@ For the EU site use `datadoghq.eu`; for US3 / US5 see Datadog's region matrix.
|
|
|
166
166
|
|
|
167
167
|
### Step 3: Map Datadog span tags
|
|
168
168
|
|
|
169
|
-
Datadog uses `service`, `resource`, `operation
|
|
169
|
+
Datadog uses `service`, `resource`, `operation`. OTel uses `service.name`, `http.route`, span name. autotel handles the conversion automatically when exporting via `dd-api-key`. If you have custom Datadog tags in dashboards, rename them in code:
|
|
170
170
|
|
|
171
171
|
| Datadog tag | OTel attribute |
|
|
172
172
|
| ----------- | --------------------------- |
|
|
@@ -185,7 +185,7 @@ Datadog uses `service`, `resource`, `operation` — OTel uses `service.name`, `h
|
|
|
185
185
|
|
|
186
186
|
## From New Relic Node agent
|
|
187
187
|
|
|
188
|
-
New Relic's agent is invasive
|
|
188
|
+
New Relic's agent is invasive. It patches Node internals. Plan a maintenance window for the cutover.
|
|
189
189
|
|
|
190
190
|
### Step 1: Remove `--require newrelic`
|
|
191
191
|
|
|
@@ -214,7 +214,7 @@ For EU: `https://otlp.eu01.nr-data.net/v1/traces`.
|
|
|
214
214
|
|
|
215
215
|
## From Honeycomb Beelines
|
|
216
216
|
|
|
217
|
-
Beelines for Node was Honeycomb's pre-OTel SDK. Migration is straightforward
|
|
217
|
+
Beelines for Node was Honeycomb's pre-OTel SDK. Migration is straightforward. Honeycomb supports OTLP natively.
|
|
218
218
|
|
|
219
219
|
```typescript
|
|
220
220
|
init({
|
|
@@ -234,7 +234,7 @@ init({
|
|
|
234
234
|
|
|
235
235
|
Both are deprecated; the migration is "rewrite the tracer setup, leave call sites alone." OpenTracing's `Tracer.startSpan` and OpenCensus's `tracer.startRootSpan` shapes are similar enough that a script can replace them with `trace()` calls in most files.
|
|
236
236
|
|
|
237
|
-
For libraries you don't control that still use OpenTracing, the OTel project ships a [shim](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-shim-opentracing)
|
|
237
|
+
For libraries you don't control that still use OpenTracing, the OTel project ships a [shim](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-shim-opentracing). Wire it once, then migrate at your own pace.
|
|
238
238
|
|
|
239
239
|
## From unstructured logging
|
|
240
240
|
|
|
@@ -249,21 +249,21 @@ See [`review-otel-patterns`](../review-otel-patterns/SKILL.md) for the framework
|
|
|
249
249
|
|
|
250
250
|
## Verifying the cutover
|
|
251
251
|
|
|
252
|
-
| Check | How
|
|
253
|
-
| --------------------------- |
|
|
254
|
-
| **Span volume matches** | Compare `count(spans)` per route over 24h; should be within ±5 %
|
|
255
|
-
| **p99 latency unchanged** | Histograms on both backends
|
|
256
|
-
| **Error rate unchanged** | `count(spans where status=error)`
|
|
257
|
-
| **Trace correlation works** | Pick 10 random `traceId`s; confirm cross-service spans resolve
|
|
258
|
-
| **Bundle size acceptable** | `pnpm bundle-size
|
|
252
|
+
| Check | How |
|
|
253
|
+
| --------------------------- | -------------------------------------------------------------------------------------------- |
|
|
254
|
+
| **Span volume matches** | Compare `count(spans)` per route over 24h; should be within ±5 % |
|
|
255
|
+
| **p99 latency unchanged** | Histograms on both backends |
|
|
256
|
+
| **Error rate unchanged** | `count(spans where status=error)` |
|
|
257
|
+
| **Trace correlation works** | Pick 10 random `traceId`s; confirm cross-service spans resolve |
|
|
258
|
+
| **Bundle size acceptable** | `pnpm bundle-size`: moving from heavy agents (New Relic, Datadog) often _shrinks_ the bundle |
|
|
259
259
|
|
|
260
260
|
## Anti-patterns
|
|
261
261
|
|
|
262
262
|
| Anti-pattern | Fix |
|
|
263
263
|
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
264
|
-
| Both old SDK and autotel running on the same library | Pick one
|
|
264
|
+
| Both old SDK and autotel running on the same library | Pick one: double-instrumentation duplicates spans |
|
|
265
265
|
| Removing the old SDK in the same PR as adding autotel | Run both side-by-side for 24–48 h first |
|
|
266
266
|
| Changing span names during migration | Preserve names; rename in a separate PR after dashboards re-pointed |
|
|
267
267
|
| No metric snapshot before cutover | Take p50/p95/p99 + error-rate baselines first |
|
|
268
|
-
| Migrating prod before staging | Always staging first
|
|
268
|
+
| Migrating prod before staging | Always staging first: at least 24 h |
|
|
269
269
|
| Trusting the old vendor agent's auto-instrumentation list | autotel's targeted instrumentations (`autotel-drizzle`, `autotel-mongoose`, …) are faster and tighter; expect to add a couple |
|
|
@@ -17,7 +17,7 @@ license: MIT
|
|
|
17
17
|
|
|
18
18
|
# Review OpenTelemetry patterns
|
|
19
19
|
|
|
20
|
-
Review and improve OpenTelemetry instrumentation in TypeScript/JavaScript codebases using autotel. Replace ad-hoc tracing with idiomatic OTel-native spans, metrics and structured logs that work across every major framework and edge runtime
|
|
20
|
+
Review and improve OpenTelemetry instrumentation in TypeScript/JavaScript codebases using autotel. Replace ad-hoc tracing with idiomatic OTel-native spans, metrics and structured logs that work across every major framework and edge runtime. Without vendor lock-in.
|
|
21
21
|
|
|
22
22
|
## When to use
|
|
23
23
|
|
|
@@ -64,7 +64,7 @@ npm install autotel-sentry # Sentry exporter via OTLP
|
|
|
64
64
|
|
|
65
65
|
### Next.js (App Router)
|
|
66
66
|
|
|
67
|
-
Step 1
|
|
67
|
+
Step 1: Initialise once in `instrumentation.ts`:
|
|
68
68
|
|
|
69
69
|
```typescript
|
|
70
70
|
// instrumentation.ts
|
|
@@ -82,7 +82,7 @@ export function register() {
|
|
|
82
82
|
}
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
Step 2
|
|
85
|
+
Step 2: Wrap route handlers:
|
|
86
86
|
|
|
87
87
|
```typescript
|
|
88
88
|
// app/api/checkout/route.ts
|
|
@@ -96,9 +96,9 @@ export const POST = withAutotel(async (request: Request) => {
|
|
|
96
96
|
});
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
Step 3
|
|
99
|
+
Step 3: Tag Server Actions the same way (`withAutotel`).
|
|
100
100
|
|
|
101
|
-
Step 4
|
|
101
|
+
Step 4: Browser to server trace propagation: drop in `<TraceProvider />` from `autotel-web` so the W3C `traceparent` header is forwarded automatically.
|
|
102
102
|
|
|
103
103
|
### Nuxt + Nitro v3
|
|
104
104
|
|
|
@@ -149,14 +149,13 @@ export const Route = createRootRoute({
|
|
|
149
149
|
|
|
150
150
|
```typescript
|
|
151
151
|
import { Hono } from 'hono';
|
|
152
|
-
import {
|
|
152
|
+
import { autotelMiddleware, useLogger } from 'autotel-adapters/hono';
|
|
153
153
|
|
|
154
|
-
const { useLogger, withAutotel } = honoToolkit;
|
|
155
154
|
const app = new Hono();
|
|
156
|
-
app.use('*',
|
|
155
|
+
app.use('*', autotelMiddleware());
|
|
157
156
|
|
|
158
157
|
app.get('/api/users', (c) => {
|
|
159
|
-
const log = useLogger(
|
|
158
|
+
const log = useLogger();
|
|
160
159
|
log.set({ users: { count: 42 } });
|
|
161
160
|
return c.json({ users: [] });
|
|
162
161
|
});
|
|
@@ -168,7 +167,7 @@ The `autotel-adapters` toolkit ships a uniform shape for these: `withAutotel` mi
|
|
|
168
167
|
|
|
169
168
|
### Cloudflare Workers (with auto `waitUntil`)
|
|
170
169
|
|
|
171
|
-
`defineWorkerFetch` instruments the handler **and** wires `ctx.waitUntil` for span exports
|
|
170
|
+
`defineWorkerFetch` instruments the handler **and** wires `ctx.waitUntil` for span exports. Without it, async exports silently drop:
|
|
172
171
|
|
|
173
172
|
```typescript
|
|
174
173
|
import { defineWorkerFetch } from 'autotel-cloudflare';
|
|
@@ -182,7 +181,7 @@ export default defineWorkerFetch(
|
|
|
182
181
|
);
|
|
183
182
|
```
|
|
184
183
|
|
|
185
|
-
For broader use cases (`scheduled`, `queue`, `email` handlers, Durable Objects, Workflows), use `wrapModule` / `wrapDurableObject` / `instrumentWorkflow
|
|
184
|
+
For broader use cases (`scheduled`, `queue`, `email` handlers, Durable Objects, Workflows), use `wrapModule` / `wrapDurableObject` / `instrumentWorkflow`. Same auto-`waitUntil` semantics.
|
|
186
185
|
|
|
187
186
|
### AWS Lambda
|
|
188
187
|
|
|
@@ -245,16 +244,19 @@ Enrichers turn raw request data into standard, low-cardinality span attributes.
|
|
|
245
244
|
| `requestSize(reqHeaders, resHeaders?)` | `http.request.body.size`, `http.response.body.size` | `content-length` headers |
|
|
246
245
|
|
|
247
246
|
```typescript
|
|
247
|
+
import { withTracing } from 'autotel';
|
|
248
248
|
import { userAgent, geo, requestSize } from 'autotel/enrichers';
|
|
249
249
|
|
|
250
|
-
export const handler =
|
|
251
|
-
ctx
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
250
|
+
export const handler = withTracing({ name: 'http.request' })(
|
|
251
|
+
(ctx) => async (request: Request) => {
|
|
252
|
+
ctx.setAttributes({
|
|
253
|
+
...userAgent(request.headers),
|
|
254
|
+
...geo(request.headers),
|
|
255
|
+
...requestSize(request.headers),
|
|
256
|
+
});
|
|
257
|
+
// ... handle request
|
|
258
|
+
},
|
|
259
|
+
);
|
|
258
260
|
```
|
|
259
261
|
|
|
260
262
|
For your own derived fields on a request's wide event, build a reusable enricher with `defineEnricher` (from `autotel`) instead of scattering ad-hoc field writes. `compute` returns an object that is merged into the named `field`; return `undefined` to skip. Keep the output low-cardinality (bucket or hash high-cardinality values):
|
|
@@ -279,7 +281,7 @@ const enrichTier = defineEnricher<
|
|
|
279
281
|
|
|
280
282
|
## Backends (multi-vendor OTLP)
|
|
281
283
|
|
|
282
|
-
Switch backends with **no code changes
|
|
284
|
+
Switch backends with **no code changes**. Autotel speaks OTLP HTTP/JSON and HTTP/protobuf out of the box.
|
|
283
285
|
|
|
284
286
|
| Backend | Endpoint | Headers |
|
|
285
287
|
| -------------------------------- | ---------------------------------------------------------- | ------------------------------------- |
|
|
@@ -334,7 +336,7 @@ const config: AttributeRedactorConfig = {
|
|
|
334
336
|
init({ attributeRedactor: config });
|
|
335
337
|
```
|
|
336
338
|
|
|
337
|
-
For free-text fields outside the span pipeline (logs, error messages, frontend payloads), use `createStringRedactor('default')
|
|
339
|
+
For free-text fields outside the span pipeline (logs, error messages, frontend payloads), use `createStringRedactor('default')`. Same masks, returns a `(s: string) => string`.
|
|
338
340
|
|
|
339
341
|
---
|
|
340
342
|
|
|
@@ -365,7 +367,7 @@ export const otelConfig = defineConfig({
|
|
|
365
367
|
});
|
|
366
368
|
```
|
|
367
369
|
|
|
368
|
-
Errors are isolated per item
|
|
370
|
+
Errors are isolated per item. One bad processor cannot break the others. See [references/processor-pipeline.md](references/processor-pipeline.md) for the full pipeline cookbook.
|
|
369
371
|
|
|
370
372
|
---
|
|
371
373
|
|
|
@@ -380,15 +382,15 @@ Errors are isolated per item — one bad processor cannot break the others. See
|
|
|
380
382
|
| `BaggageSpanProcessor` | Lift baggage entries onto every span |
|
|
381
383
|
| `PrettyConsoleExporter` | Hierarchical colourised output for local dev |
|
|
382
384
|
|
|
383
|
-
Compose them at build time with `composeSpanProcessors([...])
|
|
385
|
+
Compose them at build time with `composeSpanProcessors([...])`. No boilerplate.
|
|
384
386
|
|
|
385
387
|
---
|
|
386
388
|
|
|
387
389
|
## AI SDK integration (gen-ai semantic conventions)
|
|
388
390
|
|
|
389
|
-
autotel implements the **OTel gen-ai semantic conventions** out of the box. Token usage, tool calls, model info, latency, cost
|
|
391
|
+
autotel implements the **OTel gen-ai semantic conventions** out of the box. Token usage, tool calls, model info, latency, cost. Captured as standard attributes (`gen_ai.usage.input_tokens`, `gen_ai.tool.name`, `gen_ai.response.finish_reasons`, …) so any backend that understands OTel can render LLM telemetry without custom mapping.
|
|
390
392
|
|
|
391
|
-
> Node.js apps get the same canonical `gen_ai.*` conventions (plus cost, metric views, and agent governance) from the `autotel-genai` package
|
|
393
|
+
> Node.js apps get the same canonical `gen_ai.*` conventions (plus cost, metric views, and agent governance) from the `autotel-genai` package. `traceGenAI` / `recordGenAiUsage` from `autotel-genai/trace` and `genAiMetricViews` from `autotel-genai/metrics`. `withAiTelemetry` below is the edge-runtime entry point.
|
|
392
394
|
|
|
393
395
|
```typescript
|
|
394
396
|
import { trace } from 'autotel';
|
|
@@ -423,7 +425,7 @@ Anti-patterns to detect:
|
|
|
423
425
|
|
|
424
426
|
## Structured errors
|
|
425
427
|
|
|
426
|
-
Throw rich errors that carry status, audience, and remediation hints
|
|
428
|
+
Throw rich errors that carry status, audience, and remediation hints. And consume them at HTTP boundaries:
|
|
427
429
|
|
|
428
430
|
```typescript
|
|
429
431
|
import { createStructuredError, parseError } from 'autotel';
|
|
@@ -492,21 +494,21 @@ pnpm --filter autotel run test:e2e
|
|
|
492
494
|
|
|
493
495
|
## Anti-patterns to detect
|
|
494
496
|
|
|
495
|
-
| Anti-pattern | Fix
|
|
496
|
-
| --------------------------------------------------- |
|
|
497
|
-
| `console.log` in handlers | Use `useLogger()
|
|
498
|
-
| Manual `tracer.startSpan` boilerplate | `trace(fn)
|
|
499
|
-
| `try { … } catch (e) { console.error(e); throw e }` | Replace with `createStructuredError({ … })`
|
|
500
|
-
| `throw new Error('something went wrong')` | `createStructuredError({ message, status, why, fix })`
|
|
501
|
-
| Ad-hoc `span.setAttribute('user_id', id)` | Use `useLogger().set({ user: { id } })
|
|
502
|
-
| Multiple exporters wired in parallel by hand | `composeSpanProcessors([…])`
|
|
503
|
-
| PII in attributes | `attributeRedactor: 'default'` (on in prod by default)
|
|
504
|
-
| Cloudflare Workers without `waitUntil` | Use `defineWorkerFetch` / `wrapModule`
|
|
505
|
-
| High-cardinality span names (`/users/123`) | `SpanNameNormalizingProcessor`
|
|
506
|
-
| AI SDK token logs | `withAiTelemetry()` + gen-ai semantic conventions
|
|
507
|
-
| Health checks blowing up trace volume | `FilteringSpanProcessor`
|
|
508
|
-
| No tests for instrumentation | `InMemorySpanExporter` + `autotel-vitest` matchers
|
|
509
|
-
| Manual context propagation in fetch | `instrumentation.instrumentGlobalFetch: true` (default)
|
|
497
|
+
| Anti-pattern | Fix |
|
|
498
|
+
| --------------------------------------------------- | ------------------------------------------------------------------ |
|
|
499
|
+
| `console.log` in handlers | Use `useLogger()`: fields land on the active span |
|
|
500
|
+
| Manual `tracer.startSpan` boilerplate | `trace(fn)`: auto-named, auto-ended, auto-status |
|
|
501
|
+
| `try { … } catch (e) { console.error(e); throw e }` | Replace with `createStructuredError({ … })` |
|
|
502
|
+
| `throw new Error('something went wrong')` | `createStructuredError({ message, status, why, fix })` |
|
|
503
|
+
| Ad-hoc `span.setAttribute('user_id', id)` | Use `useLogger().set({ user: { id } })`: flattens with stable keys |
|
|
504
|
+
| Multiple exporters wired in parallel by hand | `composeSpanProcessors([…])` |
|
|
505
|
+
| PII in attributes | `attributeRedactor: 'default'` (on in prod by default) |
|
|
506
|
+
| Cloudflare Workers without `waitUntil` | Use `defineWorkerFetch` / `wrapModule` |
|
|
507
|
+
| High-cardinality span names (`/users/123`) | `SpanNameNormalizingProcessor` |
|
|
508
|
+
| AI SDK token logs | `withAiTelemetry()` + gen-ai semantic conventions |
|
|
509
|
+
| Health checks blowing up trace volume | `FilteringSpanProcessor` |
|
|
510
|
+
| No tests for instrumentation | `InMemorySpanExporter` + `autotel-vitest` matchers |
|
|
511
|
+
| Manual context propagation in fetch | `instrumentation.instrumentGlobalFetch: true` (default) |
|
|
510
512
|
|
|
511
513
|
See [references/code-review.md](references/code-review.md) for the full checklist.
|
|
512
514
|
|
|
@@ -530,7 +532,7 @@ See [references/code-review.md](references/code-review.md) for the full checklis
|
|
|
530
532
|
|
|
531
533
|
## Loading reference files
|
|
532
534
|
|
|
533
|
-
Load based on what you're working on
|
|
535
|
+
Load based on what you're working on. **do not load all at once**:
|
|
534
536
|
|
|
535
537
|
- Designing spans → [references/wide-spans.md](references/wide-spans.md)
|
|
536
538
|
- Improving errors → [references/structured-errors.md](references/structured-errors.md)
|
|
@@ -7,7 +7,7 @@ Run through this list when adding observability to a new service or auditing an
|
|
|
7
7
|
- [ ] **Service name set.** `service.name` resource attribute is unique per deployable unit (not just `"app"`).
|
|
8
8
|
- [ ] **OTLP endpoint configured** via `OTLP_ENDPOINT` env var. Don't hard-code per-vendor URLs.
|
|
9
9
|
- [ ] **No global SDK init in handlers.** Init runs once at module load (Next.js `instrumentation.ts`, Workers top of module, Node `--require`).
|
|
10
|
-
- [ ] **Production redaction on.** `attributeRedactor: 'default'` (or `'strict'` / `'pci-dss'`)
|
|
10
|
+
- [ ] **Production redaction on.** `attributeRedactor: 'default'` (or `'strict'` / `'pci-dss'`): autotel turns it on automatically when `NODE_ENV === 'production'`.
|
|
11
11
|
- [ ] **Sampling configured.** Don't ship 100% in production unless volume is genuinely tiny. `sampling.rates: { server: 25 }` is a reasonable starting point.
|
|
12
12
|
|
|
13
13
|
## Spans
|
|
@@ -31,8 +31,8 @@ Run through this list when adding observability to a new service or auditing an
|
|
|
31
31
|
- [ ] **`useLogger().set({ … })` instead of `console.log`.** Logger fields land on the active span automatically.
|
|
32
32
|
- [ ] **No PII in attributes** (or rely on redactor). Don't log raw email / cards / phones / JWTs.
|
|
33
33
|
- [ ] **Group fields with objects.** `{ user: { id, plan } }`, not flat `userId` / `userPlan`.
|
|
34
|
-
- [ ] **Decisions captured.** Which branch, which fallback, which feature flag
|
|
35
|
-
- [ ] **Background work uses `log.fork()
|
|
34
|
+
- [ ] **Decisions captured.** Which branch, which fallback, which feature flag: not just inputs.
|
|
35
|
+
- [ ] **Background work uses `log.fork()`**: gets its own span and `_parentCorrelationId` for correlation.
|
|
36
36
|
|
|
37
37
|
## Errors
|
|
38
38
|
|
|
@@ -44,7 +44,7 @@ Run through this list when adding observability to a new service or auditing an
|
|
|
44
44
|
## Metrics
|
|
45
45
|
|
|
46
46
|
- [ ] **Use OTel meter API**, not service-specific clients.
|
|
47
|
-
- [ ] **Counters for events, histograms for durations, gauges for snapshots
|
|
47
|
+
- [ ] **Counters for events, histograms for durations, gauges for snapshots**: match the right type.
|
|
48
48
|
- [ ] **Bounded label cardinality.** Don't put `userId` on a metric label.
|
|
49
49
|
|
|
50
50
|
## AI / LLM
|
|
@@ -89,7 +89,7 @@ const normalise = new SpanNameNormalizingProcessor({
|
|
|
89
89
|
});
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
Now `GET /users/123e4567-e89b-12d3-a456-426614174000/orders` becomes `GET /users/:id/orders` in your traces
|
|
92
|
+
Now `GET /users/123e4567-e89b-12d3-a456-426614174000/orders` becomes `GET /users/:id/orders` in your traces. Fewer unique span names, dramatically faster queries.
|
|
93
93
|
|
|
94
94
|
## Lift baggage onto every span
|
|
95
95
|
|
|
@@ -103,7 +103,7 @@ spanProcessors: composeSpanProcessors([baggage, new BatchSpanProcessor(otlp)]);
|
|
|
103
103
|
|
|
104
104
|
## Subscribers for in-process side effects
|
|
105
105
|
|
|
106
|
-
Subscribers run synchronously in the parent context
|
|
106
|
+
Subscribers run synchronously in the parent context. Ideal for metrics, audit, and cost calculation that you want recorded **before** the span goes to the batcher.
|
|
107
107
|
|
|
108
108
|
```typescript
|
|
109
109
|
import type { EdgeSubscriber } from 'autotel-edge';
|
|
@@ -192,7 +192,7 @@ export const otelConfig = defineConfig({
|
|
|
192
192
|
|
|
193
193
|
## Error isolation
|
|
194
194
|
|
|
195
|
-
Every compose helper catches errors per item and logs to `console.error` with the helper name. A single bad processor cannot break the others
|
|
195
|
+
Every compose helper catches errors per item and logs to `console.error` with the helper name. A single bad processor cannot break the others. Important when one of your subscribers is a third-party integration (Datadog, PagerDuty, …) that can rate-limit or 502.
|
|
196
196
|
|
|
197
197
|
## Choosing between subscribers and post-processors
|
|
198
198
|
|
|
@@ -98,5 +98,5 @@ app.onError((error, c) => {
|
|
|
98
98
|
| `throw new Error('something went wrong')` | `createStructuredError({ message, status, why, fix })` |
|
|
99
99
|
| Putting support IDs in `message` (`"Failed for user 42"`) | Use `internal: { userId: 42 }` |
|
|
100
100
|
| Returning `details: { error: stack }` to clients | Stack traces stay in `cause` / span; never serialise them out |
|
|
101
|
-
| `console.error(e); throw e` | Just throw
|
|
101
|
+
| `console.error(e); throw e` | Just throw: autotel's span will pick up the exception |
|
|
102
102
|
| Two callers throwing different shapes for the same condition | Centralise: `function declined(reason: string) { throw createStructuredError({ … }) }` |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Designing wide spans
|
|
2
2
|
|
|
3
|
-
A wide span is a single span per logical unit of work (request, job, message, fork) carrying _all_ the fields you'd ever want to filter or group by. autotel lets you build them with `useLogger().set({ … })
|
|
3
|
+
A wide span is a single span per logical unit of work (request, job, message, fork) carrying _all_ the fields you'd ever want to filter or group by. autotel lets you build them with `useLogger().set({ … })`. Fields are flattened to OTel attributes with stable dotted keys.
|
|
4
4
|
|
|
5
5
|
## Anatomy
|
|
6
6
|
|
|
@@ -50,7 +50,7 @@ payment.authCode=auth_x
|
|
|
50
50
|
2. **Group with objects.** `{ user: { id, plan } }` not `userId` / `userPlan`. The flatten step keeps the key shape stable.
|
|
51
51
|
3. **Capture decisions, not just inputs.** Which branch ran, which promo applied, which fallback fired.
|
|
52
52
|
4. **Keep cardinality bounded.** Don't put per-request UUIDs in `span.name`; use `SpanNameNormalizingProcessor`. Free-text labels go in attributes.
|
|
53
|
-
5. **Avoid raw bodies.** Pick the shape: `{ user: { id, plan } }
|
|
53
|
+
5. **Avoid raw bodies.** Pick the shape: `{ user: { id, plan } }`: never `log.set({ user: requestBody })`.
|
|
54
54
|
6. **Trust the redactor.** PII you forgot to think about (emails, JWTs, cards) gets masked in production. See `attributeRedactor: 'default'`.
|
|
55
55
|
|
|
56
56
|
## When you need correlated child spans
|
|
@@ -30,14 +30,14 @@ Total cost = (spans/sec × $/span) + (storage_GB × $/GB-month)
|
|
|
30
30
|
Head sampling reduces this directly.
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Head sampling makes a decision **at span start
|
|
34
|
-
Tail sampling makes the decision **at span end
|
|
33
|
+
Head sampling makes a decision **at span start**: fast but coarse, since it cannot know whether the span will fail.
|
|
34
|
+
Tail sampling makes the decision **at span end**: slower and heavier on storage, but precise.
|
|
35
35
|
|
|
36
36
|
The right mix:
|
|
37
37
|
|
|
38
38
|
- **Head sample at the entry point** to keep volume tractable.
|
|
39
39
|
- **Tail keep** the high-value subset (errors, slow, AI, debug-headered).
|
|
40
|
-
- **Don't sample audit spans
|
|
40
|
+
- **Don't sample audit spans**: separate processor, see [`build-audit-trails`](../build-audit-trails/SKILL.md).
|
|
41
41
|
|
|
42
42
|
## Head sampling recipes
|
|
43
43
|
|
|
@@ -73,7 +73,7 @@ sampling: {
|
|
|
73
73
|
|
|
74
74
|
### Cloudflare Workers (per-colo budget)
|
|
75
75
|
|
|
76
|
-
Workers run distributed
|
|
76
|
+
Workers run distributed. Head sampling is your friend because there's no central queue:
|
|
77
77
|
|
|
78
78
|
```typescript
|
|
79
79
|
defineWorkerFetch(
|
|
@@ -85,7 +85,7 @@ defineWorkerFetch(
|
|
|
85
85
|
);
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
## Tail sampling
|
|
88
|
+
## Tail sampling: keep interesting traces
|
|
89
89
|
|
|
90
90
|
Tail sampling looks at the full trace (root span + children) before deciding. autotel ships `TailSamplingProcessor`:
|
|
91
91
|
|
|
@@ -138,9 +138,9 @@ spanProcessors: composeSpanProcessors([
|
|
|
138
138
|
|
|
139
139
|
LLM calls produce 5–50 spans per request and are 100× more expensive than a typical handler call. Tradeoffs:
|
|
140
140
|
|
|
141
|
-
- **Don't head-sample AI handlers below 50
|
|
142
|
-
- **Always tail-keep AI traces
|
|
143
|
-
- **Cost-aware sampling
|
|
141
|
+
- **Don't head-sample AI handlers below 50 %**: debugging "why did the model loop" requires the full chain.
|
|
142
|
+
- **Always tail-keep AI traces**: the `gen_ai.*` attributes flag them.
|
|
143
|
+
- **Cost-aware sampling**: keep all calls above a $ threshold:
|
|
144
144
|
|
|
145
145
|
```typescript
|
|
146
146
|
keep: (trace) => {
|
|
@@ -176,7 +176,79 @@ if (request.headers.get('x-debug-trace') === '1') {
|
|
|
176
176
|
}
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
Now any user can mark a request as "trace this fully" by sending the header
|
|
179
|
+
Now any user can mark a request as "trace this fully" by sending the header. Invaluable for reproducing customer reports.
|
|
180
|
+
|
|
181
|
+
## Keeping the trace whole across services
|
|
182
|
+
|
|
183
|
+
`RandomSampler` rolls the dice in each process. The API can keep a trace its
|
|
184
|
+
worker drops, which leaves a waterfall with holes and no way to tell a dropped
|
|
185
|
+
span from a fast one. `DeterministicSampler` hashes a key that travels with the
|
|
186
|
+
request, so every service reaches the same verdict:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { DeterministicSampler } from 'autotel/sampling';
|
|
190
|
+
import { trace } from '@opentelemetry/api';
|
|
191
|
+
|
|
192
|
+
init({
|
|
193
|
+
service: 'checkout',
|
|
194
|
+
sampler: new DeterministicSampler({
|
|
195
|
+
sampleRate: 0.1,
|
|
196
|
+
key: () => trace.getActiveSpan()?.spanContext().traceId,
|
|
197
|
+
}),
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Give every service the same rate and the same key. Different rates break the
|
|
202
|
+
agreement again.
|
|
203
|
+
|
|
204
|
+
## Per-key target rates
|
|
205
|
+
|
|
206
|
+
A single rate cannot fit skewed traffic. At 1 % your busiest endpoint still
|
|
207
|
+
floods storage while the rare tenant whose failures you need disappears.
|
|
208
|
+
`KeyTargetRateSampler` counts traffic per key over a rolling window and gives
|
|
209
|
+
each key its own rate, so every key contributes about the same number of
|
|
210
|
+
events:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { KeyTargetRateSampler } from 'autotel/sampling';
|
|
214
|
+
|
|
215
|
+
new KeyTargetRateSampler({
|
|
216
|
+
key: (context) => context.operationName,
|
|
217
|
+
targetPerKey: 10, // ~10 events per key per window
|
|
218
|
+
windowMs: 30_000,
|
|
219
|
+
maxKeys: 1000, // keys past this share one overflow bucket
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
The first window keeps everything, because no traffic history exists yet. Rates
|
|
224
|
+
apply from the second window on.
|
|
225
|
+
|
|
226
|
+
## Recording the rate
|
|
227
|
+
|
|
228
|
+
Sampled counts lie unless you record what you discarded. A query over a 1 %
|
|
229
|
+
sample reports a hundredth of your traffic, and the number looks plausible
|
|
230
|
+
enough to act on.
|
|
231
|
+
|
|
232
|
+
autotel writes `autotel.sampling.rate` on the span as "1 in N", so
|
|
233
|
+
`COUNT * rate` estimates the population. It appears only when N exceeds 1, so
|
|
234
|
+
fully captured spans stay clean. A custom sampler joins in by implementing
|
|
235
|
+
`sampleRate()`:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import type { Sampler } from 'autotel/sampling';
|
|
239
|
+
|
|
240
|
+
class TenantSampler implements Sampler {
|
|
241
|
+
shouldSample(context) {
|
|
242
|
+
/* … */
|
|
243
|
+
}
|
|
244
|
+
sampleRate() {
|
|
245
|
+
return 20; // each kept event stands for 20
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Reach for `hashUnitInterval` from `autotel/sampling` when you need the same
|
|
251
|
+
spread for your own keys.
|
|
180
252
|
|
|
181
253
|
## Sizing the rate
|
|
182
254
|
|
|
@@ -188,11 +260,11 @@ spans/sec ≈ requests/sec × spans_per_request × head_rate × tail_keep_rate
|
|
|
188
260
|
|
|
189
261
|
Worked example for a 100 req/s API with 8 spans/req:
|
|
190
262
|
|
|
191
|
-
| Head rate | Tail keep | Result
|
|
192
|
-
| --------- | -------------------------------- |
|
|
193
|
-
| 100 % | 100 % | 800 spans/sec
|
|
194
|
-
| 10 % | 100 % (errors + slow + AI ≈ 5 %) | ≈ 110 spans/sec
|
|
195
|
-
| 1 % | 100 % | ≈ 18 spans/sec
|
|
263
|
+
| Head rate | Tail keep | Result |
|
|
264
|
+
| --------- | -------------------------------- | ------------------------------------------- |
|
|
265
|
+
| 100 % | 100 % | 800 spans/sec: expensive |
|
|
266
|
+
| 10 % | 100 % (errors + slow + AI ≈ 5 %) | ≈ 110 spans/sec: sweet spot |
|
|
267
|
+
| 1 % | 100 % | ≈ 18 spans/sec: too sparse for p99 alerting |
|
|
196
268
|
|
|
197
269
|
For per-vendor pricing:
|
|
198
270
|
|
|
@@ -208,8 +280,11 @@ For per-vendor pricing:
|
|
|
208
280
|
| 1 % sampling with no tail keep | You'll miss every interesting failure |
|
|
209
281
|
| Forgetting to tail-keep errors | Sampled traces with errors → silent customer pain |
|
|
210
282
|
| Same rate for `server` and `internal` | Internal sub-spans are 5–20× more numerous; sample harder |
|
|
211
|
-
| Ratio-based sampling on service entry point | Use parent-based
|
|
283
|
+
| Ratio-based sampling on service entry point | Use parent-based: children of a sampled trace stay together |
|
|
212
284
|
| Head-sampling AI calls below 50 % | Debugging tool loops requires the full chain |
|
|
213
285
|
| Audit spans subject to sampling | Route them to a separate processor (see `build-audit-trails`) |
|
|
214
286
|
| Tail processor before exporter (loses spans) | Tail processor goes between head sampler and remote exporter |
|
|
215
|
-
| Rate-by-route hand-coded in handlers | Use head sampler + tail keep
|
|
287
|
+
| Rate-by-route hand-coded in handlers | Use head sampler + tail keep: declarative, one place |
|
|
288
|
+
| Counting sampled spans as the population | Multiply by `autotel.sampling.rate` |
|
|
289
|
+
| `RandomSampler` on a multi-service trace | `DeterministicSampler` keyed on the trace id keeps it whole |
|
|
290
|
+
| One flat rate over skewed traffic | `KeyTargetRateSampler` gives rare keys their own rate |
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"attribute-redacting-processor-DtTS9xxh.d.cts","names":[],"sources":["../src/attribute-redacting-processor.ts"],"mappings":";;;;;;;KAsCY,mBAAA,IACV,GAAA,UACA,KAAA,EAAO,cAAA,KACJ,cAAc;;AAuBJ;AAMf;KAxBY,uBAAA;;;AAwBiD;KAnBjD,MAAA,IAAU,KAAa;;;;UAKlB,kBAAA;EA8BM;EA5BrB,IAAA;EAqCW;EAnCX,OAAA,EAAS,MAAA;EAmCqB;EAjC9B,WAAA;EAec;EAbd,IAAA,GAAO,MAAM;AAAA;;;;KAMH,kBAAA,gBAAkC,eAAe;;;;UAK5C,uBAAA;EAoBe;EAlB9B,WAAA,GAAc,MAAA;EAwBC;EArBf,aAAA,GAAgB,kBAAA;;EAGhB,KAAA;EAmBA;EAhBA,QAAA,aAAqB,kBAAA;EAgBe;EAbpC,QAAA,GAAW,MAAA;EAagD;EAV3D,WAAA;EA6BQ;EA1BR,QAAA,GAAW,mBAAA;AAAA;;;;UAMI,kCAAA;EACf,QAAA,EAAU,uBAAA,GAA0B,uBAAuB;AAAA;;;;cAMhD,iBAAA;EAAA;;;;;;;;;;;;;cAmBA,eAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAoHA,gBAAA,EAAkB,MAAA,CAC7B,uBAAA,EACA,uBAAA;AAvDkB;AAqDpB;;;AArDoB,iBAsGJ,gCAAA,CACd,GAAA,EAAK,uBAAA,GAA0B,uBAAA,aAC9B,uBAAA,GAA0B,uBAAA;;;;;;;iBA4NpB,kBAAA,CACP,IAAA,EAAM,YAAA,EACN,QAAA,EAAU,mBAAA,GACT,YAAA;;AAhRsB;AA+CzB;;;;;;;;;;;iBAwQgB,uBAAA,CACd,MAAA,EAAQ,uBAAA,GAA0B,uBAAA,GACjC,mBAAA;;;;AAxQiD;AAsDnD;;;;;;;;cAkOY,2BAAA,YAAuC,aAAA;EAAA,iBACjC,gBAAA;EAAA,iBACA,QAAA;cAGf,gBAAA,EAAkB,aAAA,EAClB,OAAA,EAAS,kCAAA;EA/DV;;AAAY;EAyEb,OAAA,CAAQ,IAAA,EAAM,IAAA,EAAM,aAAA,EAAe,OAAA;EAlCE;;;EAyCrC,KAAA,CAAM,IAAA,EAAM,YAAA;EAWZ,UAAA,IAAc,OAAA;EAId,QAAA,IAAY,OAAA;AAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"attribute-redacting-processor-DtTS9xxh.d.ts","names":[],"sources":["../src/attribute-redacting-processor.ts"],"mappings":";;;;;;;KAsCY,mBAAA,IACV,GAAA,UACA,KAAA,EAAO,cAAA,KACJ,cAAc;;AAuBJ;AAMf;KAxBY,uBAAA;;;AAwBiD;KAnBjD,MAAA,IAAU,KAAa;;;;UAKlB,kBAAA;EA8BM;EA5BrB,IAAA;EAqCW;EAnCX,OAAA,EAAS,MAAA;EAmCqB;EAjC9B,WAAA;EAec;EAbd,IAAA,GAAO,MAAM;AAAA;;;;KAMH,kBAAA,gBAAkC,eAAe;;;;UAK5C,uBAAA;EAoBe;EAlB9B,WAAA,GAAc,MAAA;EAwBC;EArBf,aAAA,GAAgB,kBAAA;;EAGhB,KAAA;EAmBA;EAhBA,QAAA,aAAqB,kBAAA;EAgBe;EAbpC,QAAA,GAAW,MAAA;EAagD;EAV3D,WAAA;EA6BQ;EA1BR,QAAA,GAAW,mBAAA;AAAA;;;;UAMI,kCAAA;EACf,QAAA,EAAU,uBAAA,GAA0B,uBAAuB;AAAA;;;;cAMhD,iBAAA;EAAA;;;;;;;;;;;;;cAmBA,eAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAoHA,gBAAA,EAAkB,MAAA,CAC7B,uBAAA,EACA,uBAAA;AAvDkB;AAqDpB;;;AArDoB,iBAsGJ,gCAAA,CACd,GAAA,EAAK,uBAAA,GAA0B,uBAAA,aAC9B,uBAAA,GAA0B,uBAAA;;;;;;;iBA4NpB,kBAAA,CACP,IAAA,EAAM,YAAA,EACN,QAAA,EAAU,mBAAA,GACT,YAAA;;AAhRsB;AA+CzB;;;;;;;;;;;iBAwQgB,uBAAA,CACd,MAAA,EAAQ,uBAAA,GAA0B,uBAAA,GACjC,mBAAA;;;;AAxQiD;AAsDnD;;;;;;;;cAkOY,2BAAA,YAAuC,aAAA;EAAA,iBACjC,gBAAA;EAAA,iBACA,QAAA;cAGf,gBAAA,EAAkB,aAAA,EAClB,OAAA,EAAS,kCAAA;EA/DV;;AAAY;EAyEb,OAAA,CAAQ,IAAA,EAAM,IAAA,EAAM,aAAA,EAAe,OAAA;EAlCE;;;EAyCrC,KAAA,CAAM,IAAA,EAAM,YAAA;EAWZ,UAAA,IAAc,OAAA;EAId,QAAA,IAAY,OAAA;AAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-log-line-processor-BcRuAdRk.d.ts","names":[],"sources":["../src/processors/canonical-log-line-processor.ts"],"mappings":";;;;;AA6Ce;AAGf;;AAHe,KATH,mBAAA,IACV,GAAA,UACA,KAAA,EAAO,cAAA,KACJ,cAAc;AAAA,UAEF,qBAAA;EACf,IAAA,EAAM,YAAA;EACN,KAAA;EACA,OAAA;EACA,KAAA,EAAO,MAAM;AAAA;AAAA,UAGE,aAAA;EASuB;EAPtC,MAAA;EASS;EAPT,UAAA;EAqBoB;EAnBpB,IAAA;AAAA;AAAA,UAGe,uBAAA;EA4BgC;EA1B/C,MAAA,GAAS,MAAA;EA4BiD;EA1B1D,aAAA;EAFA;EAIA,QAAA;EAFA;EAIA,aAAA,IAAiB,IAAA,EAAM,YAAA;EAAvB;EAEA,yBAAA;EAFiB;;;;;EAQjB,iBAAA,GAAoB,mBAAA;EAEN;EAAd,UAAA,IAAc,GAAA,EAAK,qBAAA;EAQZ;;;;;;;EAAP,IAAA,GAAO,aAAA;EAIyB;EAFhC,KAAA,IAAS,GAAA,EAAK,qBAAA,YAAiC,OAAA;EAOzC;EALN,YAAA,IAAgB,KAAA,WAAgB,GAAA,EAAK,qBAAA;EAiE1B;;;;EA5DX,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4SyB;;;;;;;;;;;;;;;;;;;;cAhPd,yBAAA,YAAqC,aAAA;EAAA,QACxC,MAAA;EAAA,QACA,aAAA;EAAA,QACA,QAAA;EAAA,QACA,aAAA;EAAA,QACA,yBAAA;EAAA,QACA,iBAAA;EAAA,QACA,UAAA;EAAA,QACA,KAAA;EAAA,QACA,YAAA;EAAA,QACA,MAAA;EAAA,QACA,aAAA;cAGI,OAAA,GAAS,uBAAA;EAAA,QAsBb,kBAAA;EA8BR,OAAA;EAIA,KAAA,CAAM,IAAA,EAAM,YAAA;EAAA,QA+CJ,qBAAA;EAAA,QA+BA,gBAAA;EAAA,QAcA,aAAA;EAAA,QAQA,WAAA;EAAA,QA0BA,WAAA;EAAA,QAeA,SAAA;EAAA,QAKA,iBAAA;EAAA,QAUA,qBAAA;EAUF,UAAA,IAAc,OAAA;EAId,QAAA,IAAY,OAAA;AAAA"}
|