autotel 4.2.5 → 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 +10 -15
- 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 +11 -16
- 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 +13 -1
- package/dist/test-span-collector.cjs.map +1 -1
- package/dist/test-span-collector.d.cts +8 -1
- package/dist/test-span-collector.d.cts.map +1 -1
- package/dist/test-span-collector.d.ts +8 -1
- package/dist/test-span-collector.d.ts.map +1 -1
- package/dist/test-span-collector.js +13 -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.cjs +27 -0
- package/dist/tracer-provider.cjs.map +1 -1
- package/dist/tracer-provider.d.cts +19 -2
- package/dist/tracer-provider.d.cts.map +1 -1
- package/dist/tracer-provider.d.ts +19 -2
- package/dist/tracer-provider.d.ts.map +1 -1
- package/dist/tracer-provider.js +27 -1
- package/dist/tracer-provider.js.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-BCtxvYir.cjs +0 -1315
- package/dist/functional-BCtxvYir.cjs.map +0 -1
- package/dist/functional-CrAq8Az8.js +0 -1265
- package/dist/functional-CrAq8Az8.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
|
@@ -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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-log-line-processor-CcrDi6TO.cjs","names":["logs","SeverityNumber"],"sources":["../src/pretty-log-formatter.ts","../src/processors/canonical-log-line-processor.ts"],"sourcesContent":["import type { CanonicalLogLineEvent } from './processors/canonical-log-line-processor';\n\nconst RESET = '\\x1b[0m';\nconst DIM = '\\x1b[2m';\nconst BOLD = '\\x1b[1m';\nconst RED = '\\x1b[31m';\nconst YELLOW = '\\x1b[33m';\nconst GREEN = '\\x1b[32m';\nconst CYAN = '\\x1b[36m';\nconst GRAY = '\\x1b[90m';\n\nconst LEVEL_COLORS: Record<string, string> = {\n debug: GRAY,\n info: GREEN,\n warn: YELLOW,\n error: RED,\n};\n\n/** Internal OTel attributes to skip in pretty output. */\nconst SKIP_PREFIXES = [\n 'telemetry.',\n 'otel.',\n 'process.',\n 'os.',\n 'host.',\n 'service.',\n 'autotel.',\n];\n\nconst SKIP_KEYS = new Set([\n 'operation',\n 'traceId',\n 'spanId',\n 'correlationId',\n 'duration_ms',\n 'duration',\n 'status_code',\n 'status_message',\n 'timestamp',\n 'http.request.method',\n 'url.path',\n 'http.route',\n 'http.response.status_code',\n]);\n\nfunction useColor(): boolean {\n if (typeof process !== 'undefined') {\n if (process.env.NO_COLOR) return false;\n if (process.env.FORCE_COLOR) return true;\n if (process.stdout?.isTTY) return true;\n }\n return false;\n}\n\nfunction c(color: string, text: string): string {\n return useColor() ? `${color}${text}${RESET}` : text;\n}\n\n/**\n * Format milliseconds into a human-readable duration string.\n *\n * @example\n * formatDuration(45) // \"45ms\"\n * formatDuration(1234) // \"1.2s\"\n * formatDuration(65000) // \"1m 5s\"\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) return `${Math.round(ms)}ms`;\n if (ms < 60_000) {\n const seconds = ms / 1000;\n return seconds < 10 ? `${seconds.toFixed(1)}s` : `${Math.round(seconds)}s`;\n }\n const minutes = Math.floor(ms / 60_000);\n const seconds = Math.round((ms % 60_000) / 1000);\n return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso);\n return d.toLocaleTimeString('en-GB', { hour12: false });\n } catch {\n return iso.slice(11, 19);\n }\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value);\n if (value == null) return '';\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Group flat dot-notation attributes into a nested tree for pretty display.\n * e.g. { 'user.id': '1', 'user.plan': 'pro' } → { user: { id: '1', plan: 'pro' } }\n */\nfunction groupAttributes(\n event: Record<string, unknown>,\n): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(event)) {\n if (SKIP_KEYS.has(key)) continue;\n if (SKIP_PREFIXES.some((p) => key.startsWith(p))) continue;\n if (value == null || value === '') continue;\n\n const parts = key.split('.');\n if (parts.length === 1) {\n tree[key] = value;\n } else {\n let current = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!;\n if (!(part in current) || typeof current[part] !== 'object') {\n current[part] = {};\n }\n current = current[part] as Record<string, unknown>;\n }\n current[parts[parts.length - 1]!] = value;\n }\n }\n\n return tree;\n}\n\nfunction renderTree(\n obj: Record<string, unknown>,\n indent: string,\n isLast: boolean[],\n): string[] {\n const lines: string[] = [];\n const entries = Object.entries(obj);\n\n entries.forEach(([key, value], idx) => {\n const last = idx === entries.length - 1;\n const connector = last ? '\\u2514\\u2500' : '\\u251c\\u2500';\n const prefix = indent + connector + ' ';\n\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const nested = value as Record<string, unknown>;\n const flatValues = Object.entries(nested).filter(\n ([, v]) => typeof v !== 'object' || v === null,\n );\n const nestedObjs = Object.entries(nested).filter(\n ([, v]) => typeof v === 'object' && v !== null && !Array.isArray(v),\n );\n\n if (nestedObjs.length === 0) {\n const inline = flatValues\n .map(([k, v]) => `${c(CYAN, k)}=${formatValue(v)}`)\n .join(' ');\n lines.push(`${prefix}${c(BOLD, key)}: ${inline}`);\n } else {\n lines.push(`${prefix}${c(BOLD, key)}:`);\n const nextIndent = indent + (last ? ' ' : '\\u2502 ');\n lines.push(...renderTree(nested, nextIndent, [...isLast, last]));\n }\n } else {\n lines.push(`${prefix}${c(CYAN, key)}: ${c(DIM, formatValue(value))}`);\n }\n });\n\n return lines;\n}\n\n/**\n * Format a canonical log line event as a pretty tree for development output.\n */\nexport function formatPrettyLogLine(ctx: CanonicalLogLineEvent): string {\n const { event, level, message } = ctx;\n\n const timestamp = formatTime(String(event.timestamp ?? ''));\n const service = event['service.name'] || event.service || '';\n const method = event['http.request.method'] || '';\n const path = event['http.route'] || event['url.path'] || '';\n const status = event['http.response.status_code'] || event.status_code || '';\n const durationMs = Number(event.duration_ms ?? 0);\n const duration = formatDuration(durationMs);\n\n const levelColor = LEVEL_COLORS[level] ?? '';\n const levelStr = c(levelColor, level.toUpperCase().padEnd(5));\n\n const parts = [c(DIM, timestamp), levelStr];\n if (service) parts.push(c(DIM, `[${service}]`));\n if (method) parts.push(c(BOLD, String(method)));\n if (path) parts.push(String(path));\n if (status) {\n const statusNum = Number(status);\n const statusColor =\n statusNum >= 500 ? RED : statusNum >= 400 ? YELLOW : GREEN;\n parts.push(c(statusColor, String(status)));\n }\n parts.push(c(DIM, `in ${duration}`));\n\n const header = parts.join(' ');\n\n const tree = groupAttributes(event);\n if (Object.keys(tree).length === 0) {\n return header;\n }\n\n const treeLines = renderTree(tree, ' ', []);\n return [header, ...treeLines].join('\\n');\n}\n","/**\n * Canonical Log Line Processor\n *\n * Automatically emits spans as canonical log lines (wide events) when they end.\n * Implements canonical log line\" pattern: one comprehensive\n * event per request with all context.\n *\n * When a span ends, this processor creates a log record with ALL span attributes,\n * making the span itself the canonical log line that can be queried like structured data.\n *\n * @example\n * ```typescript\n * import { init } from 'autotel';\n *\n * init({\n * service: 'my-app',\n * canonicalLogLines: {\n * enabled: true,\n * rootSpansOnly: true, // One canonical log line per request\n * },\n * });\n * ```\n */\n\nimport type {\n SpanProcessor,\n ReadableSpan,\n} from '@opentelemetry/sdk-trace-base';\nimport type { Attributes, AttributeValue } from '@opentelemetry/api';\nimport { logs, SeverityNumber } from '@opentelemetry/api-logs';\nimport type { Logger } from '../logger';\nimport { formatPrettyLogLine, formatDuration } from '../pretty-log-formatter';\n\n/**\n * Function to redact sensitive attribute values\n */\nexport type AttributeRedactorFn = (\n key: string,\n value: AttributeValue,\n) => AttributeValue;\n\nexport interface CanonicalLogLineEvent {\n span: ReadableSpan;\n level: 'debug' | 'info' | 'warn' | 'error';\n message: string;\n event: Record<string, unknown>;\n}\n\nexport interface KeepCondition {\n /** Keep events where HTTP status >= this value. */\n status?: number;\n /** Keep events where duration_ms >= this value. */\n durationMs?: number;\n /** Keep events matching this path pattern (simple prefix match). */\n path?: string;\n}\n\nexport interface CanonicalLogLineOptions {\n /** Logger to use for emitting canonical log lines (defaults to OTel Logs API) */\n logger?: Logger;\n /** Only emit canonical log lines for root spans (default: false) */\n rootSpansOnly?: boolean;\n /** Minimum log level for canonical log lines (default: 'info') */\n minLevel?: 'debug' | 'info' | 'warn' | 'error';\n /** Custom message format (default: uses span name) */\n messageFormat?: (span: ReadableSpan) => string;\n /** Whether to include resource attributes (default: true) */\n includeResourceAttributes?: boolean;\n /**\n * Attribute redactor function to apply before logging.\n * This ensures sensitive data is redacted in canonical log lines,\n * matching the behavior of attributeRedactor in init().\n */\n attributeRedactor?: AttributeRedactorFn;\n /** Predicate to decide whether to emit (runs after event is built). */\n shouldEmit?: (ctx: CanonicalLogLineEvent) => boolean;\n /**\n * Declarative tail sampling conditions (OR logic). If any condition matches,\n * the event is kept. Ignored when `shouldEmit` is provided.\n *\n * @example\n * keep: [{ status: 500 }, { durationMs: 1000 }]\n */\n keep?: KeepCondition[];\n /** Callback invoked after emit for custom fan-out. */\n drain?: (ctx: CanonicalLogLineEvent) => void | Promise<void>;\n /** Handler for drain failures. */\n onDrainError?: (error: unknown, ctx: CanonicalLogLineEvent) => void;\n /**\n * Pretty-print canonical log lines to console in a tree format.\n * Defaults to true when NODE_ENV is 'development'.\n */\n pretty?: boolean;\n}\n\n/**\n * Span processor that automatically emits spans as canonical log lines\n *\n * When a span ends, this processor creates a log record with ALL span attributes.\n * This implements the \"canonical log line\" pattern: one comprehensive event\n * per request with all context, queryable as structured data.\n *\n * **Key Benefits:**\n * - One log line per request with all context (wide event)\n * - High-cardinality, high-dimensionality data for powerful queries\n * - Automatic - no manual logging needed\n * - Works with any logger or OTel Logs API\n *\n * @example Basic usage\n * ```typescript\n * import { init } from 'autotel';\n *\n * init({\n * service: 'checkout-api',\n * canonicalLogLines: {\n * enabled: true,\n * rootSpansOnly: true, // One canonical log line per request\n * },\n * });\n * ```\n *\n * @example With custom logger\n * ```typescript\n * import pino from 'pino';\n * import { init } from 'autotel';\n *\n * const logger = pino();\n * init({\n * service: 'my-app',\n * logger,\n * canonicalLogLines: {\n * enabled: true,\n * logger, // Use Pino for canonical log lines\n * rootSpansOnly: true,\n * },\n * });\n * ```\n *\n * @example Custom message format\n * ```typescript\n * init({\n * service: 'my-app',\n * canonicalLogLines: {\n * enabled: true,\n * messageFormat: (span) => {\n * const status = span.status.code === 2 ? 'ERROR' : 'SUCCESS';\n * return `${span.name} [${status}]`;\n * },\n * },\n * });\n * ```\n */\nexport class CanonicalLogLineProcessor implements SpanProcessor {\n private logger?: Logger;\n private rootSpansOnly: boolean;\n private minLevel: 'debug' | 'info' | 'warn' | 'error';\n private messageFormat: (span: ReadableSpan) => string;\n private includeResourceAttributes: boolean;\n private attributeRedactor?: AttributeRedactorFn;\n private shouldEmit?: (ctx: CanonicalLogLineEvent) => boolean;\n private drain?: (ctx: CanonicalLogLineEvent) => void | Promise<void>;\n private onDrainError?: (error: unknown, ctx: CanonicalLogLineEvent) => void;\n private pretty: boolean;\n private getOTelLogger: (() => ReturnType<typeof logs.getLogger>) | null =\n null;\n\n constructor(options: CanonicalLogLineOptions = {}) {\n this.logger = options.logger;\n this.rootSpansOnly = options.rootSpansOnly ?? false;\n this.minLevel = options.minLevel ?? 'info';\n this.messageFormat =\n options.messageFormat ?? ((span) => `[${span.name}] Request completed`);\n this.includeResourceAttributes = options.includeResourceAttributes ?? true;\n this.attributeRedactor = options.attributeRedactor;\n this.shouldEmit =\n options.shouldEmit ?? this.buildKeepPredicate(options.keep);\n this.drain = options.drain;\n this.onDrainError = options.onDrainError;\n this.pretty =\n options.pretty ??\n (typeof process !== 'undefined' &&\n process.env.NODE_ENV === 'development');\n\n if (!this.logger) {\n this.getOTelLogger = () => logs.getLogger('autotel.canonical-log-line');\n }\n }\n\n private buildKeepPredicate(\n keep?: KeepCondition[],\n ): ((ctx: CanonicalLogLineEvent) => boolean) | undefined {\n if (!keep || keep.length === 0) return undefined;\n\n return (ctx: CanonicalLogLineEvent) => {\n return keep.some((condition) => {\n if (condition.status !== undefined) {\n const httpStatus = Number(\n ctx.event['http.response.status_code'] ?? 0,\n );\n if (httpStatus >= condition.status) return true;\n }\n if (\n condition.durationMs !== undefined &&\n Number(ctx.event.duration_ms ?? 0) >= condition.durationMs\n ) {\n return true;\n }\n if (condition.path !== undefined) {\n const route = String(\n ctx.event['http.route'] ?? ctx.event['url.path'] ?? '',\n );\n if (route.startsWith(condition.path)) return true;\n }\n return false;\n });\n };\n }\n\n onStart(): void {\n // No-op\n }\n\n onEnd(span: ReadableSpan): void {\n if (\n this.rootSpansOnly &&\n span.parentSpanContext?.spanId &&\n !span.parentSpanContext.isRemote\n ) {\n return;\n }\n\n const level = this.getLogLevel(span);\n if (!this.shouldLog(level)) {\n return;\n }\n\n const canonicalLogLine = this.buildCanonicalLogLine(span);\n const message = this.messageFormat(span);\n const eventContext: CanonicalLogLineEvent = {\n span,\n level,\n message,\n event: canonicalLogLine,\n };\n\n if (this.shouldEmit && !this.shouldEmit(eventContext)) return;\n\n if (this.pretty) {\n console.log(formatPrettyLogLine(eventContext));\n }\n\n if (this.logger) {\n this.emitViaLogger(level, message, canonicalLogLine);\n } else if (this.getOTelLogger) {\n const otelLogger = this.getOTelLogger();\n this.emitViaOTel(level, message, canonicalLogLine, otelLogger);\n }\n\n if (this.drain) {\n Promise.resolve(this.drain(eventContext)).catch((error) => {\n if (this.onDrainError) {\n this.onDrainError(error, eventContext);\n return;\n }\n this.reportInternalWarning('canonicalLogLines.drain failed', error);\n });\n }\n }\n\n private buildCanonicalLogLine(span: ReadableSpan): Record<string, unknown> {\n const durationMs = span.duration[0] * 1000 + span.duration[1] / 1_000_000;\n const timestamp = new Date(\n span.startTime[0] * 1000 + span.startTime[1] / 1_000_000,\n ).toISOString();\n\n // Span attributes first so core metadata fields below take precedence\n const canonicalLogLine: Record<string, unknown> = {};\n const attributes = this.redactAttributes(span.attributes);\n Object.assign(canonicalLogLine, attributes);\n\n if (this.includeResourceAttributes) {\n const resourceAttrs = this.redactAttributes(\n span.resource.attributes as Attributes,\n );\n Object.assign(canonicalLogLine, resourceAttrs);\n }\n\n canonicalLogLine.operation = span.name;\n canonicalLogLine.traceId = span.spanContext().traceId;\n canonicalLogLine.spanId = span.spanContext().spanId;\n canonicalLogLine.correlationId = span.spanContext().traceId.slice(0, 16);\n canonicalLogLine.duration_ms = Math.round(durationMs * 100) / 100;\n canonicalLogLine.duration = formatDuration(durationMs);\n canonicalLogLine.status_code = span.status.code;\n canonicalLogLine.status_message = span.status.message || undefined;\n canonicalLogLine.timestamp = timestamp;\n\n return canonicalLogLine;\n }\n\n private redactAttributes(attributes: Attributes): Record<string, unknown> {\n if (!this.attributeRedactor) {\n return { ...attributes };\n }\n\n const redacted: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== undefined) {\n redacted[key] = this.attributeRedactor(key, value);\n }\n }\n return redacted;\n }\n\n private emitViaLogger(\n level: 'debug' | 'info' | 'warn' | 'error',\n message: string,\n canonicalLogLine: Record<string, unknown>,\n ): void {\n this.logger;\n }\n\n private emitViaOTel(\n level: 'debug' | 'info' | 'warn' | 'error',\n message: string,\n canonicalLogLine: Record<string, unknown>,\n otelLogger: ReturnType<typeof logs.getLogger>,\n ): void {\n const otelAttributes: Record<string, string | number | boolean> = {};\n for (const [key, value] of Object.entries(canonicalLogLine)) {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n otelAttributes[key] = value;\n } else if (value !== null && value !== undefined) {\n otelAttributes[key] = String(value);\n }\n }\n otelLogger.emit({\n severityNumber: this.getSeverityNumber(level),\n severityText: level.toUpperCase(),\n body: message,\n attributes: otelAttributes,\n });\n }\n\n private getLogLevel(span: ReadableSpan): 'debug' | 'info' | 'warn' | 'error' {\n const explicitLevel = span.attributes['autotel.log.level'];\n if (\n explicitLevel === 'debug' ||\n explicitLevel === 'info' ||\n explicitLevel === 'warn' ||\n explicitLevel === 'error'\n ) {\n return explicitLevel;\n }\n\n if (span.status.code === 2) return 'error';\n return 'info';\n }\n\n private shouldLog(level: string): boolean {\n const levels = ['debug', 'info', 'warn', 'error'];\n return levels.indexOf(level) >= levels.indexOf(this.minLevel);\n }\n\n private getSeverityNumber(level: string): SeverityNumber {\n const mapping: Record<string, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n };\n return mapping[level] ?? SeverityNumber.INFO;\n }\n\n private reportInternalWarning(message: string, error: unknown): void {\n const err =\n error instanceof Error ? error.message : String(error ?? 'unknown error');\n if (this.logger) {\n this.logger.warn({ error: err }, `[autotel] ${message}`);\n return;\n }\n console.warn(`[autotel] ${message}: ${err}`);\n }\n\n async forceFlush(): Promise<void> {\n // No-op\n }\n\n async shutdown(): Promise<void> {\n // No-op\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-log-line-processor-FLezvFCB.js","names":[],"sources":["../src/pretty-log-formatter.ts","../src/processors/canonical-log-line-processor.ts"],"sourcesContent":["import type { CanonicalLogLineEvent } from './processors/canonical-log-line-processor';\n\nconst RESET = '\\x1b[0m';\nconst DIM = '\\x1b[2m';\nconst BOLD = '\\x1b[1m';\nconst RED = '\\x1b[31m';\nconst YELLOW = '\\x1b[33m';\nconst GREEN = '\\x1b[32m';\nconst CYAN = '\\x1b[36m';\nconst GRAY = '\\x1b[90m';\n\nconst LEVEL_COLORS: Record<string, string> = {\n debug: GRAY,\n info: GREEN,\n warn: YELLOW,\n error: RED,\n};\n\n/** Internal OTel attributes to skip in pretty output. */\nconst SKIP_PREFIXES = [\n 'telemetry.',\n 'otel.',\n 'process.',\n 'os.',\n 'host.',\n 'service.',\n 'autotel.',\n];\n\nconst SKIP_KEYS = new Set([\n 'operation',\n 'traceId',\n 'spanId',\n 'correlationId',\n 'duration_ms',\n 'duration',\n 'status_code',\n 'status_message',\n 'timestamp',\n 'http.request.method',\n 'url.path',\n 'http.route',\n 'http.response.status_code',\n]);\n\nfunction useColor(): boolean {\n if (typeof process !== 'undefined') {\n if (process.env.NO_COLOR) return false;\n if (process.env.FORCE_COLOR) return true;\n if (process.stdout?.isTTY) return true;\n }\n return false;\n}\n\nfunction c(color: string, text: string): string {\n return useColor() ? `${color}${text}${RESET}` : text;\n}\n\n/**\n * Format milliseconds into a human-readable duration string.\n *\n * @example\n * formatDuration(45) // \"45ms\"\n * formatDuration(1234) // \"1.2s\"\n * formatDuration(65000) // \"1m 5s\"\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) return `${Math.round(ms)}ms`;\n if (ms < 60_000) {\n const seconds = ms / 1000;\n return seconds < 10 ? `${seconds.toFixed(1)}s` : `${Math.round(seconds)}s`;\n }\n const minutes = Math.floor(ms / 60_000);\n const seconds = Math.round((ms % 60_000) / 1000);\n return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso);\n return d.toLocaleTimeString('en-GB', { hour12: false });\n } catch {\n return iso.slice(11, 19);\n }\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value);\n if (value == null) return '';\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Group flat dot-notation attributes into a nested tree for pretty display.\n * e.g. { 'user.id': '1', 'user.plan': 'pro' } → { user: { id: '1', plan: 'pro' } }\n */\nfunction groupAttributes(\n event: Record<string, unknown>,\n): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(event)) {\n if (SKIP_KEYS.has(key)) continue;\n if (SKIP_PREFIXES.some((p) => key.startsWith(p))) continue;\n if (value == null || value === '') continue;\n\n const parts = key.split('.');\n if (parts.length === 1) {\n tree[key] = value;\n } else {\n let current = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!;\n if (!(part in current) || typeof current[part] !== 'object') {\n current[part] = {};\n }\n current = current[part] as Record<string, unknown>;\n }\n current[parts[parts.length - 1]!] = value;\n }\n }\n\n return tree;\n}\n\nfunction renderTree(\n obj: Record<string, unknown>,\n indent: string,\n isLast: boolean[],\n): string[] {\n const lines: string[] = [];\n const entries = Object.entries(obj);\n\n entries.forEach(([key, value], idx) => {\n const last = idx === entries.length - 1;\n const connector = last ? '\\u2514\\u2500' : '\\u251c\\u2500';\n const prefix = indent + connector + ' ';\n\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const nested = value as Record<string, unknown>;\n const flatValues = Object.entries(nested).filter(\n ([, v]) => typeof v !== 'object' || v === null,\n );\n const nestedObjs = Object.entries(nested).filter(\n ([, v]) => typeof v === 'object' && v !== null && !Array.isArray(v),\n );\n\n if (nestedObjs.length === 0) {\n const inline = flatValues\n .map(([k, v]) => `${c(CYAN, k)}=${formatValue(v)}`)\n .join(' ');\n lines.push(`${prefix}${c(BOLD, key)}: ${inline}`);\n } else {\n lines.push(`${prefix}${c(BOLD, key)}:`);\n const nextIndent = indent + (last ? ' ' : '\\u2502 ');\n lines.push(...renderTree(nested, nextIndent, [...isLast, last]));\n }\n } else {\n lines.push(`${prefix}${c(CYAN, key)}: ${c(DIM, formatValue(value))}`);\n }\n });\n\n return lines;\n}\n\n/**\n * Format a canonical log line event as a pretty tree for development output.\n */\nexport function formatPrettyLogLine(ctx: CanonicalLogLineEvent): string {\n const { event, level, message } = ctx;\n\n const timestamp = formatTime(String(event.timestamp ?? ''));\n const service = event['service.name'] || event.service || '';\n const method = event['http.request.method'] || '';\n const path = event['http.route'] || event['url.path'] || '';\n const status = event['http.response.status_code'] || event.status_code || '';\n const durationMs = Number(event.duration_ms ?? 0);\n const duration = formatDuration(durationMs);\n\n const levelColor = LEVEL_COLORS[level] ?? '';\n const levelStr = c(levelColor, level.toUpperCase().padEnd(5));\n\n const parts = [c(DIM, timestamp), levelStr];\n if (service) parts.push(c(DIM, `[${service}]`));\n if (method) parts.push(c(BOLD, String(method)));\n if (path) parts.push(String(path));\n if (status) {\n const statusNum = Number(status);\n const statusColor =\n statusNum >= 500 ? RED : statusNum >= 400 ? YELLOW : GREEN;\n parts.push(c(statusColor, String(status)));\n }\n parts.push(c(DIM, `in ${duration}`));\n\n const header = parts.join(' ');\n\n const tree = groupAttributes(event);\n if (Object.keys(tree).length === 0) {\n return header;\n }\n\n const treeLines = renderTree(tree, ' ', []);\n return [header, ...treeLines].join('\\n');\n}\n","/**\n * Canonical Log Line Processor\n *\n * Automatically emits spans as canonical log lines (wide events) when they end.\n * Implements canonical log line\" pattern: one comprehensive\n * event per request with all context.\n *\n * When a span ends, this processor creates a log record with ALL span attributes,\n * making the span itself the canonical log line that can be queried like structured data.\n *\n * @example\n * ```typescript\n * import { init } from 'autotel';\n *\n * init({\n * service: 'my-app',\n * canonicalLogLines: {\n * enabled: true,\n * rootSpansOnly: true, // One canonical log line per request\n * },\n * });\n * ```\n */\n\nimport type {\n SpanProcessor,\n ReadableSpan,\n} from '@opentelemetry/sdk-trace-base';\nimport type { Attributes, AttributeValue } from '@opentelemetry/api';\nimport { logs, SeverityNumber } from '@opentelemetry/api-logs';\nimport type { Logger } from '../logger';\nimport { formatPrettyLogLine, formatDuration } from '../pretty-log-formatter';\n\n/**\n * Function to redact sensitive attribute values\n */\nexport type AttributeRedactorFn = (\n key: string,\n value: AttributeValue,\n) => AttributeValue;\n\nexport interface CanonicalLogLineEvent {\n span: ReadableSpan;\n level: 'debug' | 'info' | 'warn' | 'error';\n message: string;\n event: Record<string, unknown>;\n}\n\nexport interface KeepCondition {\n /** Keep events where HTTP status >= this value. */\n status?: number;\n /** Keep events where duration_ms >= this value. */\n durationMs?: number;\n /** Keep events matching this path pattern (simple prefix match). */\n path?: string;\n}\n\nexport interface CanonicalLogLineOptions {\n /** Logger to use for emitting canonical log lines (defaults to OTel Logs API) */\n logger?: Logger;\n /** Only emit canonical log lines for root spans (default: false) */\n rootSpansOnly?: boolean;\n /** Minimum log level for canonical log lines (default: 'info') */\n minLevel?: 'debug' | 'info' | 'warn' | 'error';\n /** Custom message format (default: uses span name) */\n messageFormat?: (span: ReadableSpan) => string;\n /** Whether to include resource attributes (default: true) */\n includeResourceAttributes?: boolean;\n /**\n * Attribute redactor function to apply before logging.\n * This ensures sensitive data is redacted in canonical log lines,\n * matching the behavior of attributeRedactor in init().\n */\n attributeRedactor?: AttributeRedactorFn;\n /** Predicate to decide whether to emit (runs after event is built). */\n shouldEmit?: (ctx: CanonicalLogLineEvent) => boolean;\n /**\n * Declarative tail sampling conditions (OR logic). If any condition matches,\n * the event is kept. Ignored when `shouldEmit` is provided.\n *\n * @example\n * keep: [{ status: 500 }, { durationMs: 1000 }]\n */\n keep?: KeepCondition[];\n /** Callback invoked after emit for custom fan-out. */\n drain?: (ctx: CanonicalLogLineEvent) => void | Promise<void>;\n /** Handler for drain failures. */\n onDrainError?: (error: unknown, ctx: CanonicalLogLineEvent) => void;\n /**\n * Pretty-print canonical log lines to console in a tree format.\n * Defaults to true when NODE_ENV is 'development'.\n */\n pretty?: boolean;\n}\n\n/**\n * Span processor that automatically emits spans as canonical log lines\n *\n * When a span ends, this processor creates a log record with ALL span attributes.\n * This implements the \"canonical log line\" pattern: one comprehensive event\n * per request with all context, queryable as structured data.\n *\n * **Key Benefits:**\n * - One log line per request with all context (wide event)\n * - High-cardinality, high-dimensionality data for powerful queries\n * - Automatic - no manual logging needed\n * - Works with any logger or OTel Logs API\n *\n * @example Basic usage\n * ```typescript\n * import { init } from 'autotel';\n *\n * init({\n * service: 'checkout-api',\n * canonicalLogLines: {\n * enabled: true,\n * rootSpansOnly: true, // One canonical log line per request\n * },\n * });\n * ```\n *\n * @example With custom logger\n * ```typescript\n * import pino from 'pino';\n * import { init } from 'autotel';\n *\n * const logger = pino();\n * init({\n * service: 'my-app',\n * logger,\n * canonicalLogLines: {\n * enabled: true,\n * logger, // Use Pino for canonical log lines\n * rootSpansOnly: true,\n * },\n * });\n * ```\n *\n * @example Custom message format\n * ```typescript\n * init({\n * service: 'my-app',\n * canonicalLogLines: {\n * enabled: true,\n * messageFormat: (span) => {\n * const status = span.status.code === 2 ? 'ERROR' : 'SUCCESS';\n * return `${span.name} [${status}]`;\n * },\n * },\n * });\n * ```\n */\nexport class CanonicalLogLineProcessor implements SpanProcessor {\n private logger?: Logger;\n private rootSpansOnly: boolean;\n private minLevel: 'debug' | 'info' | 'warn' | 'error';\n private messageFormat: (span: ReadableSpan) => string;\n private includeResourceAttributes: boolean;\n private attributeRedactor?: AttributeRedactorFn;\n private shouldEmit?: (ctx: CanonicalLogLineEvent) => boolean;\n private drain?: (ctx: CanonicalLogLineEvent) => void | Promise<void>;\n private onDrainError?: (error: unknown, ctx: CanonicalLogLineEvent) => void;\n private pretty: boolean;\n private getOTelLogger: (() => ReturnType<typeof logs.getLogger>) | null =\n null;\n\n constructor(options: CanonicalLogLineOptions = {}) {\n this.logger = options.logger;\n this.rootSpansOnly = options.rootSpansOnly ?? false;\n this.minLevel = options.minLevel ?? 'info';\n this.messageFormat =\n options.messageFormat ?? ((span) => `[${span.name}] Request completed`);\n this.includeResourceAttributes = options.includeResourceAttributes ?? true;\n this.attributeRedactor = options.attributeRedactor;\n this.shouldEmit =\n options.shouldEmit ?? this.buildKeepPredicate(options.keep);\n this.drain = options.drain;\n this.onDrainError = options.onDrainError;\n this.pretty =\n options.pretty ??\n (typeof process !== 'undefined' &&\n process.env.NODE_ENV === 'development');\n\n if (!this.logger) {\n this.getOTelLogger = () => logs.getLogger('autotel.canonical-log-line');\n }\n }\n\n private buildKeepPredicate(\n keep?: KeepCondition[],\n ): ((ctx: CanonicalLogLineEvent) => boolean) | undefined {\n if (!keep || keep.length === 0) return undefined;\n\n return (ctx: CanonicalLogLineEvent) => {\n return keep.some((condition) => {\n if (condition.status !== undefined) {\n const httpStatus = Number(\n ctx.event['http.response.status_code'] ?? 0,\n );\n if (httpStatus >= condition.status) return true;\n }\n if (\n condition.durationMs !== undefined &&\n Number(ctx.event.duration_ms ?? 0) >= condition.durationMs\n ) {\n return true;\n }\n if (condition.path !== undefined) {\n const route = String(\n ctx.event['http.route'] ?? ctx.event['url.path'] ?? '',\n );\n if (route.startsWith(condition.path)) return true;\n }\n return false;\n });\n };\n }\n\n onStart(): void {\n // No-op\n }\n\n onEnd(span: ReadableSpan): void {\n if (\n this.rootSpansOnly &&\n span.parentSpanContext?.spanId &&\n !span.parentSpanContext.isRemote\n ) {\n return;\n }\n\n const level = this.getLogLevel(span);\n if (!this.shouldLog(level)) {\n return;\n }\n\n const canonicalLogLine = this.buildCanonicalLogLine(span);\n const message = this.messageFormat(span);\n const eventContext: CanonicalLogLineEvent = {\n span,\n level,\n message,\n event: canonicalLogLine,\n };\n\n if (this.shouldEmit && !this.shouldEmit(eventContext)) return;\n\n if (this.pretty) {\n console.log(formatPrettyLogLine(eventContext));\n }\n\n if (this.logger) {\n this.emitViaLogger(level, message, canonicalLogLine);\n } else if (this.getOTelLogger) {\n const otelLogger = this.getOTelLogger();\n this.emitViaOTel(level, message, canonicalLogLine, otelLogger);\n }\n\n if (this.drain) {\n Promise.resolve(this.drain(eventContext)).catch((error) => {\n if (this.onDrainError) {\n this.onDrainError(error, eventContext);\n return;\n }\n this.reportInternalWarning('canonicalLogLines.drain failed', error);\n });\n }\n }\n\n private buildCanonicalLogLine(span: ReadableSpan): Record<string, unknown> {\n const durationMs = span.duration[0] * 1000 + span.duration[1] / 1_000_000;\n const timestamp = new Date(\n span.startTime[0] * 1000 + span.startTime[1] / 1_000_000,\n ).toISOString();\n\n // Span attributes first so core metadata fields below take precedence\n const canonicalLogLine: Record<string, unknown> = {};\n const attributes = this.redactAttributes(span.attributes);\n Object.assign(canonicalLogLine, attributes);\n\n if (this.includeResourceAttributes) {\n const resourceAttrs = this.redactAttributes(\n span.resource.attributes as Attributes,\n );\n Object.assign(canonicalLogLine, resourceAttrs);\n }\n\n canonicalLogLine.operation = span.name;\n canonicalLogLine.traceId = span.spanContext().traceId;\n canonicalLogLine.spanId = span.spanContext().spanId;\n canonicalLogLine.correlationId = span.spanContext().traceId.slice(0, 16);\n canonicalLogLine.duration_ms = Math.round(durationMs * 100) / 100;\n canonicalLogLine.duration = formatDuration(durationMs);\n canonicalLogLine.status_code = span.status.code;\n canonicalLogLine.status_message = span.status.message || undefined;\n canonicalLogLine.timestamp = timestamp;\n\n return canonicalLogLine;\n }\n\n private redactAttributes(attributes: Attributes): Record<string, unknown> {\n if (!this.attributeRedactor) {\n return { ...attributes };\n }\n\n const redacted: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== undefined) {\n redacted[key] = this.attributeRedactor(key, value);\n }\n }\n return redacted;\n }\n\n private emitViaLogger(\n level: 'debug' | 'info' | 'warn' | 'error',\n message: string,\n canonicalLogLine: Record<string, unknown>,\n ): void {\n this.logger;\n }\n\n private emitViaOTel(\n level: 'debug' | 'info' | 'warn' | 'error',\n message: string,\n canonicalLogLine: Record<string, unknown>,\n otelLogger: ReturnType<typeof logs.getLogger>,\n ): void {\n const otelAttributes: Record<string, string | number | boolean> = {};\n for (const [key, value] of Object.entries(canonicalLogLine)) {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n otelAttributes[key] = value;\n } else if (value !== null && value !== undefined) {\n otelAttributes[key] = String(value);\n }\n }\n otelLogger.emit({\n severityNumber: this.getSeverityNumber(level),\n severityText: level.toUpperCase(),\n body: message,\n attributes: otelAttributes,\n });\n }\n\n private getLogLevel(span: ReadableSpan): 'debug' | 'info' | 'warn' | 'error' {\n const explicitLevel = span.attributes['autotel.log.level'];\n if (\n explicitLevel === 'debug' ||\n explicitLevel === 'info' ||\n explicitLevel === 'warn' ||\n explicitLevel === 'error'\n ) {\n return explicitLevel;\n }\n\n if (span.status.code === 2) return 'error';\n return 'info';\n }\n\n private shouldLog(level: string): boolean {\n const levels = ['debug', 'info', 'warn', 'error'];\n return levels.indexOf(level) >= levels.indexOf(this.minLevel);\n }\n\n private getSeverityNumber(level: string): SeverityNumber {\n const mapping: Record<string, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n };\n return mapping[level] ?? SeverityNumber.INFO;\n }\n\n private reportInternalWarning(message: string, error: unknown): void {\n const err =\n error instanceof Error ? error.message : String(error ?? 'unknown error');\n if (this.logger) {\n this.logger.warn({ error: err }, `[autotel] ${message}`);\n return;\n }\n console.warn(`[autotel] ${message}: ${err}`);\n }\n\n async forceFlush(): Promise<void> {\n // No-op\n }\n\n async shutdown(): Promise<void> {\n // No-op\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-log-line-processor-xvjMgtpF.d.cts","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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"define-event-CreknLm3.d.ts","names":[],"sources":["../src/define-event.ts"],"mappings":";;;KAIK,eAAA;EACC,OAAA;EAAe,IAAA,EAAM,CAAC;AAAA;EACtB,OAAA;EAAgB,KAAA;AAAA;AAAA,UAEL,UAAA;EACf,SAAA,CAAU,KAAA,YAAiB,eAAe,CAAC,CAAA;AAAA;AAAA,UAG5B,kBAAA;EACf,YAAA,IAAgB,MAAA,EAAQ,CAAC;AAAA;AAAA,UAGV,YAAA;EAAA,SACN,IAAA,EAAM,IAAA;EAAA,SACN,cAAA,GAAiB,mBAAA;EAC1B,KAAA,CAAM,OAAA,EAAS,OAAA;AAAA;AAAA,iBAGD,WAAA,yCAGJ,UAAA,CAAW,OAAA,GAErB,IAAA,EAAM,IAAA,EACN,MAAA,EAAQ,CAAA,EACR,OAAA,GAAS,kBAAA,CAAmB,CAAA,IAC3B,YAAA,CAAa,IAAA,EAAM,OAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"define-event-HZRizPwz.d.cts","names":[],"sources":["../src/define-event.ts"],"mappings":";;;KAIK,eAAA;EACC,OAAA;EAAe,IAAA,EAAM,CAAC;AAAA;EACtB,OAAA;EAAgB,KAAA;AAAA;AAAA,UAEL,UAAA;EACf,SAAA,CAAU,KAAA,YAAiB,eAAe,CAAC,CAAA;AAAA;AAAA,UAG5B,kBAAA;EACf,YAAA,IAAgB,MAAA,EAAQ,CAAC;AAAA;AAAA,UAGV,YAAA;EAAA,SACN,IAAA,EAAM,IAAA;EAAA,SACN,cAAA,GAAiB,mBAAA;EAC1B,KAAA,CAAM,OAAA,EAAS,OAAA;AAAA;AAAA,iBAGD,WAAA,yCAGJ,UAAA,CAAW,OAAA,GAErB,IAAA,EAAM,IAAA,EACN,MAAA,EAAQ,CAAA,EACR,OAAA,GAAS,kBAAA,CAAmB,CAAA,IAC3B,YAAA,CAAa,IAAA,EAAM,OAAA"}
|