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
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","names":[],"sources":["../src/config.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","names":[],"sources":["../src/config.ts"],"mappings":";;;cAuBa;;;;;;;;;;;;;;;;;;;;UA6BI;;;;;EAKf;;;;;EAMA;;;;;EAMA,SAAS;;;;;EAMT,QAAQ;;;;;;;;;;;;;;iBA2EM,UAAU,SAAS;;;;iBAOnB,aAAa,SAAS;EACpC,qBAAqB;;;;;iBAWP"}
|
package/dist/correlation-id.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_track = require('./track-
|
|
2
|
+
const require_track = require('./track-BI6dmZ2X.cjs');
|
|
3
3
|
|
|
4
4
|
exports.CORRELATION_ID_BAGGAGE_KEY = require_track.CORRELATION_ID_BAGGAGE_KEY;
|
|
5
5
|
exports.generateCorrelationId = require_track.generateCorrelationId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"correlation-id.d.cts","names":[],"sources":["../src/correlation-id.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"correlation-id.d.cts","names":[],"sources":["../src/correlation-id.ts"],"mappings":";;KA8BK;EACH;;;;;cAaW;;;;;;;;;;;;;;iBAeG;;;;;;;;;;;;;;;;;;;;iBA4BA;;;;;;;;;;;;;;;iBAwCA;;;;;;;;;;;;;;;;;;;iBAsBA,qBAAqB,GAAG,uBAAuB,UAAU,IAAI;;;;;;;;;;;;;;;iBAkB7D,iBAAiB;;;;;;;;;;;;;;;;;;;;;iBAwBjB,0BACd,qDAC8B;;;;iBAahB,yBAAyB,kBAAkB"}
|
package/dist/correlation-id.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"correlation-id.d.ts","names":[],"sources":["../src/correlation-id.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"correlation-id.d.ts","names":[],"sources":["../src/correlation-id.ts"],"mappings":";;KA8BK;EACH;;;;;cAaW;;;;;;;;;;;;;;iBAeG;;;;;;;;;;;;;;;;;;;;iBA4BA;;;;;;;;;;;;;;;iBAwCA;;;;;;;;;;;;;;;;;;;iBAsBA,qBAAqB,GAAG,uBAAuB,UAAU,IAAI;;;;;;;;;;;;;;;iBAkB7D,iBAAiB;;;;;;;;;;;;;;;;;;;;;iBAwBjB,0BACd,qDAC8B;;;;iBAahB,yBAAyB,kBAAkB"}
|
package/dist/correlation-id.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as CORRELATION_ID_BAGGAGE_KEY, c as getCorrelationStorage, d as setCorrelationId, f as setCorrelationIdInBaggage, l as getOrCreateCorrelationId, o as generateCorrelationId, s as getCorrelationId, u as runWithCorrelationId } from "./track-
|
|
1
|
+
import { a as CORRELATION_ID_BAGGAGE_KEY, c as getCorrelationStorage, d as setCorrelationId, f as setCorrelationIdInBaggage, l as getOrCreateCorrelationId, o as generateCorrelationId, s as getCorrelationId, u as runWithCorrelationId } from "./track-BBcxEJEC.js";
|
|
2
2
|
|
|
3
3
|
export { CORRELATION_ID_BAGGAGE_KEY, generateCorrelationId, getCorrelationId, getCorrelationStorage, getOrCreateCorrelationId, runWithCorrelationId, setCorrelationId, setCorrelationIdInBaggage };
|
package/dist/db.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.cts","names":[],"sources":["../src/db.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"db.d.cts","names":[],"sources":["../src/db.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCsB,YAAY,GAChC,kBACA,mBACA,UAAU,QAAQ,IAClB,aAAa,kCACZ,QAAQ;;;;cAsGE;;;;;;;;;;;cAYA;;;;;;;;;;;UAeI;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiDc,mBAAmB,kBACjC,QAAQ,GACR,SAAS,4BACR"}
|
package/dist/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","names":[],"sources":["../src/db.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"db.d.ts","names":[],"sources":["../src/db.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsCsB,YAAY,GAChC,kBACA,mBACA,UAAU,QAAQ,IAClB,aAAa,kCACZ,QAAQ;;;;cAsGE;;;;;;;;;;;cAYA;;;;;;;;;;;UAeI;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiDc,mBAAmB,kBACjC,QAAQ,GACR,SAAS,4BACR"}
|
package/dist/decorators.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_config = require('./config.cjs');
|
|
3
|
-
const require_track = require('./track-
|
|
3
|
+
const require_track = require('./track-BI6dmZ2X.cjs');
|
|
4
4
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
5
5
|
|
|
6
6
|
//#region src/decorators.ts
|
package/dist/decorators.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.cjs","names":["getConfig","createTraceContext","SpanStatusCode"],"sources":["../src/decorators.ts"],"sourcesContent":["/**\n * TypeScript 5+ Decorators for autotel\n *\n * Provides @Trace decorator for class-based code.\n *\n * **Requires TypeScript 5.0+**\n *\n * @example Method decorator\n * ```typescript\n * import { Trace } from 'autotel/decorators'\n *\n * class OrderService {\n * @Trace('order.create', { withMetrics: true })\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n *\n * @Trace() // Uses method name as span name\n * async processPayment(orderId: string) {\n * return await stripe.charge(orderId)\n * }\n * }\n * ```\n */\n\nimport type { TracingOptions, TraceContext } from './functional';\nimport { getConfig } from './config';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { createTraceContext } from './trace-context';\n\n/**\n * Options for @Trace method decorator\n */\nexport interface TraceDecoratorOptions extends Omit<TracingOptions, 'name'> {\n /**\n * Custom span name. If not provided, uses the method name.\n */\n name?: string;\n}\n\n/**\n * @Trace - Method decorator for fine-grained tracing\n *\n * Wraps a class method with automatic tracing. Supports both patterns:\n * - Simple: method doesn't use ctx\n * - Advanced: method accesses ctx via this.ctx\n *\n * @example Simple usage (no ctx)\n * ```typescript\n * class OrderService {\n * @Trace()\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n * }\n * ```\n *\n * @example With custom name and options\n * ```typescript\n * class PaymentService {\n * @Trace('payment.charge', { withMetrics: true })\n * async chargeCard(amount: number) {\n * return await stripe.charges.create({ amount })\n * }\n * }\n * ```\n *\n * @example Accessing ctx\n * ```typescript\n * interface WithTraceContext {\n * ctx?: TraceContext\n * }\n *\n * class UserService {\n * @Trace()\n * async createUser(data: UserData) {\n * // Access ctx via this.ctx (available during execution)\n * const ctx = (this as unknown as WithTraceContext).ctx\n * if (ctx) {\n * ctx.setAttribute('user.id', data.id)\n * }\n * return await db.users.create(data)\n * }\n * }\n * ```\n */\nexport function Trace(\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n name?: string,\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n nameOrOptions?: string | TraceDecoratorOptions,\n maybeOptions?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T {\n // Parse arguments\n const name =\n typeof nameOrOptions === 'string' ? nameOrOptions : nameOrOptions?.name;\n // Options are used in the returned decorator function, not here\n
|
|
1
|
+
{"version":3,"file":"decorators.cjs","names":["getConfig","createTraceContext","SpanStatusCode"],"sources":["../src/decorators.ts"],"sourcesContent":["/**\n * TypeScript 5+ Decorators for autotel\n *\n * Provides @Trace decorator for class-based code.\n *\n * **Requires TypeScript 5.0+**\n *\n * @example Method decorator\n * ```typescript\n * import { Trace } from 'autotel/decorators'\n *\n * class OrderService {\n * @Trace('order.create', { withMetrics: true })\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n *\n * @Trace() // Uses method name as span name\n * async processPayment(orderId: string) {\n * return await stripe.charge(orderId)\n * }\n * }\n * ```\n */\n\nimport type { TracingOptions, TraceContext } from './functional';\nimport { getConfig } from './config';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { createTraceContext } from './trace-context';\n\n/**\n * Options for @Trace method decorator\n */\nexport interface TraceDecoratorOptions extends Omit<TracingOptions, 'name'> {\n /**\n * Custom span name. If not provided, uses the method name.\n */\n name?: string;\n}\n\n/**\n * @Trace - Method decorator for fine-grained tracing\n *\n * Wraps a class method with automatic tracing. Supports both patterns:\n * - Simple: method doesn't use ctx\n * - Advanced: method accesses ctx via this.ctx\n *\n * @example Simple usage (no ctx)\n * ```typescript\n * class OrderService {\n * @Trace()\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n * }\n * ```\n *\n * @example With custom name and options\n * ```typescript\n * class PaymentService {\n * @Trace('payment.charge', { withMetrics: true })\n * async chargeCard(amount: number) {\n * return await stripe.charges.create({ amount })\n * }\n * }\n * ```\n *\n * @example Accessing ctx\n * ```typescript\n * interface WithTraceContext {\n * ctx?: TraceContext\n * }\n *\n * class UserService {\n * @Trace()\n * async createUser(data: UserData) {\n * // Access ctx via this.ctx (available during execution)\n * const ctx = (this as unknown as WithTraceContext).ctx\n * if (ctx) {\n * ctx.setAttribute('user.id', data.id)\n * }\n * return await db.users.create(data)\n * }\n * }\n * ```\n */\nexport function Trace(\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n name?: string,\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n nameOrOptions?: string | TraceDecoratorOptions,\n maybeOptions?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T {\n // Parse arguments\n const name =\n typeof nameOrOptions === 'string' ? nameOrOptions : nameOrOptions?.name;\n // Options are used in the returned decorator function, not here\n const _options: TraceDecoratorOptions =\n typeof nameOrOptions === 'string'\n ? maybeOptions || {}\n : nameOrOptions || {};\n\n // TypeScript 5+ decorator signature\n return function <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n ): T {\n const methodName = String(context.name);\n\n // Skip if not an async function\n // Check multiple ways to detect async functions (for different transpilation environments)\n // TypeScript decorators run at class definition time, so we need robust detection\n const methodStr = originalMethod?.toString() || '';\n const isAsync =\n originalMethod &&\n (originalMethod.constructor?.name === 'AsyncFunction' ||\n methodStr.trim().startsWith('async ') ||\n (methodStr.includes('[native code]') && methodStr.includes('async')) ||\n // Fallback: if function has async in its string representation\n /async\\s+/.test(methodStr));\n\n if (!isAsync) {\n // Not an async function, return as-is\n return originalMethod;\n }\n\n const spanName = name || methodName;\n\n return async function <This>(\n this: This,\n ...args: unknown[]\n ): Promise<unknown> {\n const config = getConfig();\n const tracer = config.tracer;\n\n return tracer.startActiveSpan(spanName, async (span) => {\n try {\n // Make ctx available via this.ctx for methods that need it\n const ctx: TraceContext = createTraceContext(span);\n\n const originalCtx = (this as { ctx?: TraceContext }).ctx;\n try {\n (this as { ctx?: TraceContext }).ctx = ctx;\n const result = await originalMethod.apply(this, args as []);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } finally {\n // Restore original ctx\n if (originalCtx === undefined) {\n delete (this as { ctx?: TraceContext }).ctx;\n } else {\n (this as { ctx?: TraceContext }).ctx = originalCtx;\n }\n }\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\n });\n } as T;\n };\n}\n\n// Re-export types for convenience\n\nexport { type TraceContext, type TracingOptions } from './functional';\n"],"mappings":";;;;;;AAmGA,SAAgB,MACd,eACA,cAIK;CAEL,MAAM,OACJ,OAAO,kBAAkB,WAAW,gBAAgB,eAAe;CAQrE,OAAO,SACL,gBACA,SACG;EACH,MAAM,aAAa,OAAO,QAAQ,IAAI;EAKtC,MAAM,YAAY,gBAAgB,SAAS,KAAK;EAShD,IAAI,EAPF,mBACC,eAAe,aAAa,SAAS,mBACpC,UAAU,KAAK,CAAC,CAAC,WAAW,QAAQ,KACnC,UAAU,SAAS,eAAe,KAAK,UAAU,SAAS,OAAO,KAElE,WAAW,KAAK,SAAS,KAI3B,OAAO;EAGT,MAAM,WAAW,QAAQ;EAEzB,OAAO,eAEL,GAAG,MACe;GAIlB,OAHeA,yBACK,CAAC,CAAC,OAER,gBAAgB,UAAU,OAAO,SAAS;IACtD,IAAI;KAEF,MAAM,MAAoBC,iCAAmB,IAAI;KAEjD,MAAM,cAAe,KAAgC;KACrD,IAAI;MACF,AAAC,KAAgC,MAAM;MACvC,MAAM,SAAS,MAAM,eAAe,MAAM,MAAM,IAAU;MAC1D,KAAK,UAAU,EAAE,MAAMC,kCAAe,GAAG,CAAC;MAC1C,OAAO;KACT,UAAU;MAER,IAAI,gBAAgB,QAClB,OAAQ,KAAgC;WAExC,AAAC,KAAgC,MAAM;KAE3C;IACF,SAAS,OAAO;KACd,KAAK,UAAU;MACb,MAAMA,kCAAe;MACrB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;KACpD,CAAC;KACD,KAAK,gBACH,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAC1D;KACA,MAAM;IACR,UAAU;KACR,KAAK,IAAI;IACX;GACF,CAAC;EACH;CACF;AACF"}
|
package/dist/decorators.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.cts","names":[],"sources":["../src/decorators.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"decorators.d.cts","names":[],"sources":["../src/decorators.ts"],"mappings":";;;;;;UAiCiB,8BAA8B,KAAK;;;;EAIlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiDc,MACd,UAAU,yBACR,cAAc,oBAAoB,kBACpC,gBAAgB,GAChB,SAAS,gCACN;iBACW,MACd,eACA,UAAU,yBACR,cAAc,oBAAoB,kBACpC,gBAAgB,GAChB,SAAS,gCACN"}
|
package/dist/decorators.d.ts
CHANGED
package/dist/decorators.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","names":[],"sources":["../src/decorators.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","names":[],"sources":["../src/decorators.ts"],"mappings":";;;;;;UAiCiB,8BAA8B,KAAK;;;;EAIlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiDc,MACd,UAAU,yBACR,cAAc,oBAAoB,kBACpC,gBAAgB,GAChB,SAAS,gCACN;iBACW,MACd,eACA,UAAU,yBACR,cAAc,oBAAoB,kBACpC,gBAAgB,GAChB,SAAS,gCACN"}
|
package/dist/decorators.js
CHANGED
package/dist/decorators.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.js","names":[],"sources":["../src/decorators.ts"],"sourcesContent":["/**\n * TypeScript 5+ Decorators for autotel\n *\n * Provides @Trace decorator for class-based code.\n *\n * **Requires TypeScript 5.0+**\n *\n * @example Method decorator\n * ```typescript\n * import { Trace } from 'autotel/decorators'\n *\n * class OrderService {\n * @Trace('order.create', { withMetrics: true })\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n *\n * @Trace() // Uses method name as span name\n * async processPayment(orderId: string) {\n * return await stripe.charge(orderId)\n * }\n * }\n * ```\n */\n\nimport type { TracingOptions, TraceContext } from './functional';\nimport { getConfig } from './config';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { createTraceContext } from './trace-context';\n\n/**\n * Options for @Trace method decorator\n */\nexport interface TraceDecoratorOptions extends Omit<TracingOptions, 'name'> {\n /**\n * Custom span name. If not provided, uses the method name.\n */\n name?: string;\n}\n\n/**\n * @Trace - Method decorator for fine-grained tracing\n *\n * Wraps a class method with automatic tracing. Supports both patterns:\n * - Simple: method doesn't use ctx\n * - Advanced: method accesses ctx via this.ctx\n *\n * @example Simple usage (no ctx)\n * ```typescript\n * class OrderService {\n * @Trace()\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n * }\n * ```\n *\n * @example With custom name and options\n * ```typescript\n * class PaymentService {\n * @Trace('payment.charge', { withMetrics: true })\n * async chargeCard(amount: number) {\n * return await stripe.charges.create({ amount })\n * }\n * }\n * ```\n *\n * @example Accessing ctx\n * ```typescript\n * interface WithTraceContext {\n * ctx?: TraceContext\n * }\n *\n * class UserService {\n * @Trace()\n * async createUser(data: UserData) {\n * // Access ctx via this.ctx (available during execution)\n * const ctx = (this as unknown as WithTraceContext).ctx\n * if (ctx) {\n * ctx.setAttribute('user.id', data.id)\n * }\n * return await db.users.create(data)\n * }\n * }\n * ```\n */\nexport function Trace(\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n name?: string,\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n nameOrOptions?: string | TraceDecoratorOptions,\n maybeOptions?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T {\n // Parse arguments\n const name =\n typeof nameOrOptions === 'string' ? nameOrOptions : nameOrOptions?.name;\n // Options are used in the returned decorator function, not here\n
|
|
1
|
+
{"version":3,"file":"decorators.js","names":[],"sources":["../src/decorators.ts"],"sourcesContent":["/**\n * TypeScript 5+ Decorators for autotel\n *\n * Provides @Trace decorator for class-based code.\n *\n * **Requires TypeScript 5.0+**\n *\n * @example Method decorator\n * ```typescript\n * import { Trace } from 'autotel/decorators'\n *\n * class OrderService {\n * @Trace('order.create', { withMetrics: true })\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n *\n * @Trace() // Uses method name as span name\n * async processPayment(orderId: string) {\n * return await stripe.charge(orderId)\n * }\n * }\n * ```\n */\n\nimport type { TracingOptions, TraceContext } from './functional';\nimport { getConfig } from './config';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { createTraceContext } from './trace-context';\n\n/**\n * Options for @Trace method decorator\n */\nexport interface TraceDecoratorOptions extends Omit<TracingOptions, 'name'> {\n /**\n * Custom span name. If not provided, uses the method name.\n */\n name?: string;\n}\n\n/**\n * @Trace - Method decorator for fine-grained tracing\n *\n * Wraps a class method with automatic tracing. Supports both patterns:\n * - Simple: method doesn't use ctx\n * - Advanced: method accesses ctx via this.ctx\n *\n * @example Simple usage (no ctx)\n * ```typescript\n * class OrderService {\n * @Trace()\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n * }\n * ```\n *\n * @example With custom name and options\n * ```typescript\n * class PaymentService {\n * @Trace('payment.charge', { withMetrics: true })\n * async chargeCard(amount: number) {\n * return await stripe.charges.create({ amount })\n * }\n * }\n * ```\n *\n * @example Accessing ctx\n * ```typescript\n * interface WithTraceContext {\n * ctx?: TraceContext\n * }\n *\n * class UserService {\n * @Trace()\n * async createUser(data: UserData) {\n * // Access ctx via this.ctx (available during execution)\n * const ctx = (this as unknown as WithTraceContext).ctx\n * if (ctx) {\n * ctx.setAttribute('user.id', data.id)\n * }\n * return await db.users.create(data)\n * }\n * }\n * ```\n */\nexport function Trace(\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n name?: string,\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n nameOrOptions?: string | TraceDecoratorOptions,\n maybeOptions?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T {\n // Parse arguments\n const name =\n typeof nameOrOptions === 'string' ? nameOrOptions : nameOrOptions?.name;\n // Options are used in the returned decorator function, not here\n const _options: TraceDecoratorOptions =\n typeof nameOrOptions === 'string'\n ? maybeOptions || {}\n : nameOrOptions || {};\n\n // TypeScript 5+ decorator signature\n return function <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n ): T {\n const methodName = String(context.name);\n\n // Skip if not an async function\n // Check multiple ways to detect async functions (for different transpilation environments)\n // TypeScript decorators run at class definition time, so we need robust detection\n const methodStr = originalMethod?.toString() || '';\n const isAsync =\n originalMethod &&\n (originalMethod.constructor?.name === 'AsyncFunction' ||\n methodStr.trim().startsWith('async ') ||\n (methodStr.includes('[native code]') && methodStr.includes('async')) ||\n // Fallback: if function has async in its string representation\n /async\\s+/.test(methodStr));\n\n if (!isAsync) {\n // Not an async function, return as-is\n return originalMethod;\n }\n\n const spanName = name || methodName;\n\n return async function <This>(\n this: This,\n ...args: unknown[]\n ): Promise<unknown> {\n const config = getConfig();\n const tracer = config.tracer;\n\n return tracer.startActiveSpan(spanName, async (span) => {\n try {\n // Make ctx available via this.ctx for methods that need it\n const ctx: TraceContext = createTraceContext(span);\n\n const originalCtx = (this as { ctx?: TraceContext }).ctx;\n try {\n (this as { ctx?: TraceContext }).ctx = ctx;\n const result = await originalMethod.apply(this, args as []);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } finally {\n // Restore original ctx\n if (originalCtx === undefined) {\n delete (this as { ctx?: TraceContext }).ctx;\n } else {\n (this as { ctx?: TraceContext }).ctx = originalCtx;\n }\n }\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\n });\n } as T;\n };\n}\n\n// Re-export types for convenience\n\nexport { type TraceContext, type TracingOptions } from './functional';\n"],"mappings":";;;;;AAmGA,SAAgB,MACd,eACA,cAIK;CAEL,MAAM,OACJ,OAAO,kBAAkB,WAAW,gBAAgB,eAAe;CAQrE,OAAO,SACL,gBACA,SACG;EACH,MAAM,aAAa,OAAO,QAAQ,IAAI;EAKtC,MAAM,YAAY,gBAAgB,SAAS,KAAK;EAShD,IAAI,EAPF,mBACC,eAAe,aAAa,SAAS,mBACpC,UAAU,KAAK,CAAC,CAAC,WAAW,QAAQ,KACnC,UAAU,SAAS,eAAe,KAAK,UAAU,SAAS,OAAO,KAElE,WAAW,KAAK,SAAS,KAI3B,OAAO;EAGT,MAAM,WAAW,QAAQ;EAEzB,OAAO,eAEL,GAAG,MACe;GAIlB,OAHe,UACK,CAAC,CAAC,OAER,gBAAgB,UAAU,OAAO,SAAS;IACtD,IAAI;KAEF,MAAM,MAAoB,mBAAmB,IAAI;KAEjD,MAAM,cAAe,KAAgC;KACrD,IAAI;MACF,AAAC,KAAgC,MAAM;MACvC,MAAM,SAAS,MAAM,eAAe,MAAM,MAAM,IAAU;MAC1D,KAAK,UAAU,EAAE,MAAM,eAAe,GAAG,CAAC;MAC1C,OAAO;KACT,UAAU;MAER,IAAI,gBAAgB,QAClB,OAAQ,KAAgC;WAExC,AAAC,KAAgC,MAAM;KAE3C;IACF,SAAS,OAAO;KACd,KAAK,UAAU;MACb,MAAM,eAAe;MACrB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;KACpD,CAAC;KACD,KAAK,gBACH,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAC1D;KACA,MAAM;IACR,UAAU;KACR,KAAK,IAAI;IACX;GACF,CAAC;EACH;CACF;AACF"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { i as EventSchemaMetadata } from "./event-subscriber-
|
|
2
|
-
|
|
1
|
+
import { i as EventSchemaMetadata } from "./event-subscriber-CWh8sTGh.js";
|
|
3
2
|
//#region src/define-event.d.ts
|
|
4
3
|
type SafeParseResult<T> = {
|
|
5
4
|
success: true;
|
|
@@ -22,4 +21,4 @@ interface DefinedEvent<Name extends string, Payload> {
|
|
|
22
21
|
declare function defineEvent<Name extends string, Payload, S extends SchemaLike<Payload>>(name: Name, schema: S, options?: DefineEventOptions<S>): DefinedEvent<Name, Payload>;
|
|
23
22
|
//#endregion
|
|
24
23
|
export { defineEvent as i, DefinedEvent as n, SchemaLike as r, DefineEventOptions as t };
|
|
25
|
-
//# sourceMappingURL=define-event-
|
|
24
|
+
//# sourceMappingURL=define-event-B2z1SBe7.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-event-B2z1SBe7.d.ts","names":[],"sources":["../src/define-event.ts"],"mappings":";;KAIK,gBAAgB;EACjB;EAAe,MAAM;;EAAQ;EAAgB;;UAEhC,WAAW;EAC1B,UAAU,iBAAiB,gBAAgB;;UAG5B,mBAAmB;EAClC,gBAAgB,QAAQ;;UAGT,aAAa,qBAAqB;WACxC,MAAM;WACN,iBAAiB;EAC1B,MAAM,SAAS;;iBAGD,YACd,qBACA,SACA,UAAU,WAAW,UAErB,MAAM,MACN,QAAQ,GACR,UAAS,mBAAmB,KAC3B,aAAa,MAAM"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { i as EventSchemaMetadata } from "./event-subscriber-
|
|
2
|
-
|
|
1
|
+
import { i as EventSchemaMetadata } from "./event-subscriber-CWh8sTGh.cjs";
|
|
3
2
|
//#region src/define-event.d.ts
|
|
4
3
|
type SafeParseResult<T> = {
|
|
5
4
|
success: true;
|
|
@@ -22,4 +21,4 @@ interface DefinedEvent<Name extends string, Payload> {
|
|
|
22
21
|
declare function defineEvent<Name extends string, Payload, S extends SchemaLike<Payload>>(name: Name, schema: S, options?: DefineEventOptions<S>): DefinedEvent<Name, Payload>;
|
|
23
22
|
//#endregion
|
|
24
23
|
export { defineEvent as i, DefinedEvent as n, SchemaLike as r, DefineEventOptions as t };
|
|
25
|
-
//# sourceMappingURL=define-event-
|
|
24
|
+
//# sourceMappingURL=define-event-CGG048HE.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-event-CGG048HE.d.cts","names":[],"sources":["../src/define-event.ts"],"mappings":";;KAIK,gBAAgB;EACjB;EAAe,MAAM;;EAAQ;EAAgB;;UAEhC,WAAW;EAC1B,UAAU,iBAAiB,gBAAgB;;UAG5B,mBAAmB;EAClC,gBAAgB,QAAQ;;UAGT,aAAa,qBAAqB;WACxC,MAAM;WACN,iBAAiB;EAC1B,MAAM,SAAS;;iBAGD,YACd,qBACA,SACA,UAAU,WAAW,UAErB,MAAM,MACN,QAAQ,GACR,UAAS,mBAAmB,KAC3B,aAAa,MAAM"}
|
package/dist/diagnostics.cjs
CHANGED
|
@@ -100,6 +100,15 @@ const SEVERITY = {
|
|
|
100
100
|
warn: _opentelemetry_api_logs.SeverityNumber.WARN,
|
|
101
101
|
error: _opentelemetry_api_logs.SeverityNumber.ERROR
|
|
102
102
|
};
|
|
103
|
+
/**
|
|
104
|
+
* Node publishes `console.*` channel messages as the raw argument array
|
|
105
|
+
* (e.g. `console.warn('a', 1)` → `['a', 1]`); some publishers use the
|
|
106
|
+
* `{ args: [...] }` object shape instead. Accept both.
|
|
107
|
+
*/
|
|
108
|
+
function messageArgs(message) {
|
|
109
|
+
if (Array.isArray(message)) return message;
|
|
110
|
+
return message?.args ?? [];
|
|
111
|
+
}
|
|
103
112
|
const nodeUtil = require_node_require.safeRequire("node:util");
|
|
104
113
|
/** Format console arguments the way `console` itself would (printf + inspect). */
|
|
105
114
|
function formatArgs(args) {
|
|
@@ -126,7 +135,7 @@ function captureConsole(options = {}) {
|
|
|
126
135
|
let recording = false;
|
|
127
136
|
const disposers = levels.map((level) => subscribeChannel(`console.${level}`, (message) => {
|
|
128
137
|
if (recording) return;
|
|
129
|
-
const body = formatArgs(message
|
|
138
|
+
const body = formatArgs(messageArgs(message));
|
|
130
139
|
recording = true;
|
|
131
140
|
try {
|
|
132
141
|
const attributes = {
|
package/dist/diagnostics.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.cjs","names":["safeRequire","SeverityNumber","safeRequire","logs","trace","ATTR_HTTP_REQUEST_METHOD","ATTR_URL_PATH","ATTR_URL_SCHEME","ATTR_NETWORK_PROTOCOL_VERSION","ATTR_USER_AGENT_ORIGINAL","ATTR_SERVER_ADDRESS","ATTR_SERVER_PORT","propagation","otelContext","defaultTextMapGetter","SpanKind","ATTR_URL_FULL","defaultTextMapSetter","SpanStatusCode","ATTR_HTTP_RESPONSE_STATUS_CODE"],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"sourcesContent":["/**\n * Edge-safe wrappers over Node's `diagnostics_channel`.\n *\n * The module is loaded lazily through {@link safeRequire} — never a static\n * `node:` import — so merely importing this file is side-effect-free and bundles\n * cleanly for browser/edge targets, where every subscribe call degrades to a\n * no-op (returning an unsubscribe that does nothing). This is the shared\n * primitive behind autotel's diagnostics-channel integrations (console capture,\n * HTTP spans) and any app- or library-specific channel you want to bridge into\n * a span/event.\n *\n * `diagnostics_channel.subscribe` (Node 18.7+) and `tracingChannel` (Node 19+)\n * are used; autotel targets Node 22+, but on any runtime that lacks them the\n * loader returns `undefined` and the helpers no-op.\n */\n\nimport { safeRequire } from '../node-require.js';\n\ntype DiagnosticsChannelModule = typeof import('node:diagnostics_channel');\n\nlet cached: DiagnosticsChannelModule | null | undefined;\n\nfunction loadDiagnosticsChannel(): DiagnosticsChannelModule | undefined {\n if (cached !== undefined) return cached ?? undefined;\n cached =\n safeRequire<DiagnosticsChannelModule>('node:diagnostics_channel') ?? null;\n return cached ?? undefined;\n}\n\n/** Whether Node's `diagnostics_channel` is available in this runtime. */\nexport function diagnosticsChannelAvailable(): boolean {\n return loadDiagnosticsChannel() !== undefined;\n}\n\n/** Handler for a plain named channel. */\nexport type ChannelMessageHandler = (\n message: unknown,\n name: string | symbol,\n) => void;\n\n/**\n * Subscribe to a named diagnostics channel. Returns an idempotent unsubscribe\n * function; a no-op (that still returns a disposer) on unsupported runtimes.\n */\nexport function subscribeChannel(\n name: string,\n handler: ChannelMessageHandler,\n): () => void {\n const dc = loadDiagnosticsChannel();\n if (!dc?.subscribe) return () => {};\n dc.subscribe(name, handler);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n dc.unsubscribe?.(name, handler);\n };\n}\n\n/** Subscriber set for a {@link https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel TracingChannel}. */\nexport interface TracingChannelHandlers {\n start?(message: unknown): void;\n end?(message: unknown): void;\n asyncStart?(message: unknown): void;\n asyncEnd?(message: unknown): void;\n error?(message: unknown): void;\n}\n\n/**\n * Subscribe to a `tracingChannel` (the `tracing:${name}:{start,end,…}` set).\n * Returns an idempotent unsubscribe; a no-op on runtimes without\n * `tracingChannel` support.\n */\nexport function subscribeTracingChannel(\n name: string,\n handlers: TracingChannelHandlers,\n): () => void {\n const dc = loadDiagnosticsChannel();\n const channel = dc?.tracingChannel?.(name);\n if (!channel) return () => {};\n // Node's typings want all five handlers; we pass the subset provided.\n channel.subscribe(handlers as Parameters<typeof channel.subscribe>[0]);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n channel.unsubscribe(handlers as Parameters<typeof channel.unsubscribe>[0]);\n };\n}\n","/**\n * Capture `console.*` calls as wide events — without monkey-patching `console`.\n *\n * Node publishes every `console.log` / `info` / `debug` / `warn` / `error` call\n * on a built-in diagnostics channel. {@link captureConsole} subscribes to those\n * channels and turns each call into an OpenTelemetry **log record** (correlated\n * to the active span via trace context by the logs SDK) and/or a **span event**\n * on the active span. Nothing patches the global `console`, so there is no\n * load-order fragility and no interference with other tooling.\n *\n * Opt-in. Call once after `init()` and keep the returned disposer to stop:\n *\n * ```ts\n * import { captureConsole } from 'autotel/diagnostics';\n *\n * const stop = captureConsole(); // every console.* → correlated log record\n * // …later: stop();\n * ```\n *\n * The built-in `console.*` channels are a Stability-1 (experimental) Node API;\n * this module degrades to a no-op where they are unavailable.\n */\n\nimport { trace, type Attributes } from '@opentelemetry/api';\nimport { logs, SeverityNumber, type Logger } from '@opentelemetry/api-logs';\nimport { safeRequire } from '../node-require.js';\nimport { subscribeChannel } from './channel.js';\n\n/** Console methods that publish a diagnostics channel. */\nexport type ConsoleLevel = 'log' | 'info' | 'debug' | 'warn' | 'error';\n\nconst ALL_LEVELS: readonly ConsoleLevel[] = [\n 'log',\n 'info',\n 'debug',\n 'warn',\n 'error',\n];\n\nconst SEVERITY: Record<ConsoleLevel, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n log: SeverityNumber.INFO,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n};\n\nexport interface CaptureConsoleOptions {\n /** Which console methods to capture. Defaults to all five. */\n levels?: readonly ConsoleLevel[];\n /**\n * Where to record captured output:\n * - `'log'` (default): emit an OpenTelemetry log record;\n * - `'span-event'`: add an event to the active span (nothing if no active span);\n * - `'both'`.\n */\n target?: 'log' | 'span-event' | 'both';\n /** Logger name for emitted records. Defaults to `'autotel.console'`. */\n loggerName?: string;\n /** Static attributes merged onto every captured record/event. */\n attributes?: Attributes;\n}\n\ntype ConsoleMessage = { args?: unknown[] };\n\nconst nodeUtil = safeRequire<typeof import('node:util')>('node:util');\n\n/** Format console arguments the way `console` itself would (printf + inspect). */\nfunction formatArgs(args: unknown[]): string {\n if (nodeUtil?.format) return nodeUtil.format(...args);\n return args\n .map((a) => (typeof a === 'string' ? a : safeStringify(a)))\n .join(' ');\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Start capturing `console.*` calls as wide events. Returns a disposer that\n * stops capture. Safe to call on runtimes without the console channels (no-op).\n */\nexport function captureConsole(\n options: CaptureConsoleOptions = {},\n): () => void {\n const levels = options.levels ?? ALL_LEVELS;\n const target = options.target ?? 'log';\n const toLog = target === 'log' || target === 'both';\n const toSpan = target === 'span-event' || target === 'both';\n const logger: Logger = logs.getLogger(\n options.loggerName ?? 'autotel.console',\n );\n\n // Guard against re-entrancy: if recording a captured call itself triggers a\n // `console.*` (e.g. an exporter logging a warning), don't capture that.\n let recording = false;\n\n const disposers = levels.map((level) =>\n subscribeChannel(`console.${level}`, (message) => {\n if (recording) return;\n const args = (message as ConsoleMessage)?.args ?? [];\n const body = formatArgs(args as unknown[]);\n recording = true;\n try {\n const attributes: Attributes = {\n 'log.source': 'console',\n 'log.method': level,\n ...options.attributes,\n };\n if (toLog) {\n logger.emit({\n severityNumber: SEVERITY[level],\n severityText: level.toUpperCase(),\n body,\n attributes,\n });\n }\n if (toSpan) {\n trace\n .getActiveSpan()\n ?.addEvent('log', { 'log.message': body, ...attributes });\n }\n } finally {\n recording = false;\n }\n }),\n );\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n","/**\n * Lightweight HTTP spans via Node's built-in `diagnostics_channel` — no\n * monkey-patching, no `import-in-the-middle`.\n *\n * Node publishes `http.server.request.start` / `http.server.response.finish`\n * and `http.client.request.start` / `http.client.response.finish` /\n * `http.client.request.error`. {@link instrumentHttp} subscribes to those and\n * emits a `SERVER` span per inbound request (parented to an incoming W3C\n * `traceparent`) and a `CLIENT` span per outbound request (whose context it\n * injects into the outgoing headers for downstream propagation).\n *\n * ```ts\n * import { instrumentHttp } from 'autotel/diagnostics';\n *\n * const stop = instrumentHttp();\n * ```\n *\n * Scope & limitation. This is an opt-in, low-overhead alternative to\n * `@opentelemetry/instrumentation-http` for HTTP span coverage + W3C\n * propagation. Client-side propagation works (the `traceparent` is injected on\n * the `ClientRequest` object directly). What it does **not** do is establish an\n * *ambient* OpenTelemetry context for the duration of a server request handler,\n * so application spans created inside a handler will not become children of the\n * `SERVER` span.\n *\n * This is structural, not a \"wait for a newer Node\" gap. Node publishes the\n * `http.*` channels with a plain `channel.publish()` — not `runStores` /\n * `tracingChannel` — so a subscriber has no scope to bind a store to. The only\n * ways to get handler nesting both defeat the purpose of using a channel:\n * 1. `AsyncLocalStorage.enterWith()` in the start handler — no scoped exit, so\n * context leaks across requests sharing an event-loop tick / keep-alive\n * connection and misattributes spans. Strictly worse than no nesting.\n * 2. Patching `http.Server.prototype.emit` to wrap the `'request'` listener in\n * `context.with()` — monkey-patching, i.e. reimplementing\n * `@opentelemetry/instrumentation-http`.\n * If you need handler nesting, use `@opentelemetry/instrumentation-http`.\n *\n * The `http.*` channels are a Stability-1 (experimental) Node API; this module\n * degrades to a no-op where they are unavailable.\n */\n\nimport type { ClientRequest, IncomingMessage, ServerResponse } from 'node:http';\nimport {\n context as otelContext,\n defaultTextMapGetter,\n defaultTextMapSetter,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n type Attributes,\n type Span,\n type Tracer,\n} from '@opentelemetry/api';\nimport {\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_NETWORK_PROTOCOL_VERSION,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n ATTR_URL_FULL,\n ATTR_URL_PATH,\n ATTR_URL_SCHEME,\n ATTR_USER_AGENT_ORIGINAL,\n} from '@opentelemetry/semantic-conventions';\nimport { subscribeChannel } from './channel.js';\n\nexport interface InstrumentHttpOptions {\n /** Instrument inbound (server) requests. Default `true`. */\n server?: boolean;\n /** Instrument outbound (client) requests. Default `true`. */\n client?: boolean;\n /** Tracer to use. Defaults to `trace.getTracer('autotel.http-diagnostics')`. */\n tracer?: Tracer;\n}\n\ninterface ServerStartMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ServerFinishMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ClientStartMessage {\n request?: ClientRequest;\n}\ninterface ClientFinishMessage {\n request?: ClientRequest;\n response?: IncomingMessage;\n}\ninterface ClientErrorMessage {\n request?: ClientRequest;\n error?: unknown;\n}\n\nconst SERVER_SPANS = new WeakMap<object, Span>();\nconst CLIENT_SPANS = new WeakMap<object, Span>();\n\nfunction firstHeader(value: string | string[] | undefined): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction splitHostPort(host: string | undefined): {\n address?: string;\n port?: number;\n} {\n if (!host) return {};\n const idx = host.lastIndexOf(':');\n if (idx === -1) return { address: host };\n const port = Number(host.slice(idx + 1));\n return {\n address: host.slice(0, idx),\n port: Number.isFinite(port) ? port : undefined,\n };\n}\n\n/**\n * Start emitting HTTP server/client spans from Node's HTTP diagnostics\n * channels. Returns a disposer; a no-op on runtimes without the channels.\n */\nexport function instrumentHttp(\n options: InstrumentHttpOptions = {},\n): () => void {\n const tracer = options.tracer ?? trace.getTracer('autotel.http-diagnostics');\n const disposers: Array<() => void> = [];\n\n if (options.server !== false) {\n disposers.push(\n subscribeChannel('http.server.request.start', (message) => {\n const request = (message as ServerStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n const host = firstHeader(request.headers.host);\n const { address, port } = splitHostPort(host);\n const path = (request.url ?? '/').split('?', 1)[0];\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_URL_PATH]: path,\n [ATTR_URL_SCHEME]: 'http',\n [ATTR_NETWORK_PROTOCOL_VERSION]: request.httpVersion,\n [ATTR_USER_AGENT_ORIGINAL]: firstHeader(\n request.headers['user-agent'],\n ),\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n };\n const parent = propagation.extract(\n otelContext.active(),\n request.headers,\n defaultTextMapGetter,\n );\n const span = tracer.startSpan(\n method,\n { kind: SpanKind.SERVER, attributes },\n parent,\n );\n SERVER_SPANS.set(request, span);\n }),\n subscribeChannel('http.server.response.finish', (message) => {\n const { request, response } = (message as ServerFinishMessage) ?? {};\n if (!request) return;\n const span = SERVER_SPANS.get(request);\n if (!span) return;\n SERVER_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 500);\n }),\n );\n }\n\n if (options.client !== false) {\n disposers.push(\n subscribeChannel('http.client.request.start', (message) => {\n const request = (message as ClientStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n // `ClientRequest` exposes host/protocol/path on the public surface.\n const req = request as ClientRequest & {\n host?: string;\n protocol?: string;\n path?: string;\n };\n const { address, port } = splitHostPort(req.host);\n const scheme = (req.protocol ?? 'http:').replace(':', '');\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n [ATTR_URL_FULL]:\n address && req.path\n ? `${scheme}://${req.host}${req.path}`\n : undefined,\n };\n const span = tracer.startSpan(method, {\n kind: SpanKind.CLIENT,\n attributes,\n });\n CLIENT_SPANS.set(request, span);\n\n // Inject this span's context into the outbound headers so the\n // downstream service continues the trace.\n if (!request.headersSent) {\n const carrier: Record<string, string> = {};\n propagation.inject(\n trace.setSpan(otelContext.active(), span),\n carrier,\n defaultTextMapSetter,\n );\n for (const [key, value] of Object.entries(carrier)) {\n try {\n request.setHeader(key, value);\n } catch {\n // Headers already sent / immutable — propagation best-effort.\n }\n }\n }\n }),\n subscribeChannel('http.client.response.finish', (message) => {\n const { request, response } = (message as ClientFinishMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 400);\n }),\n subscribeChannel('http.client.request.error', (message) => {\n const { request, error } = (message as ClientErrorMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n if (error instanceof Error) span.recordException(error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : undefined,\n });\n span.end();\n }),\n );\n }\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n\n/** Set status code + error status (when `>= errorAt`) and end the span. */\nfunction finishHttpSpan(\n span: Span,\n statusCode: number | undefined,\n errorAt: number,\n): void {\n if (statusCode !== undefined) {\n span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, statusCode);\n if (statusCode >= errorAt) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n }\n span.end();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"diagnostics.cjs","names":["safeRequire","SeverityNumber","safeRequire","logs","trace","ATTR_HTTP_REQUEST_METHOD","ATTR_URL_PATH","ATTR_URL_SCHEME","ATTR_NETWORK_PROTOCOL_VERSION","ATTR_USER_AGENT_ORIGINAL","ATTR_SERVER_ADDRESS","ATTR_SERVER_PORT","propagation","otelContext","defaultTextMapGetter","SpanKind","ATTR_URL_FULL","defaultTextMapSetter","SpanStatusCode","ATTR_HTTP_RESPONSE_STATUS_CODE"],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"sourcesContent":["/**\n * Edge-safe wrappers over Node's `diagnostics_channel`.\n *\n * The module is loaded lazily through {@link safeRequire} — never a static\n * `node:` import — so merely importing this file is side-effect-free and bundles\n * cleanly for browser/edge targets, where every subscribe call degrades to a\n * no-op (returning an unsubscribe that does nothing). This is the shared\n * primitive behind autotel's diagnostics-channel integrations (console capture,\n * HTTP spans) and any app- or library-specific channel you want to bridge into\n * a span/event.\n *\n * `diagnostics_channel.subscribe` (Node 18.7+) and `tracingChannel` (Node 19+)\n * are used; autotel targets Node 22+, but on any runtime that lacks them the\n * loader returns `undefined` and the helpers no-op.\n */\n\nimport { safeRequire } from '../node-require.js';\n\ntype DiagnosticsChannelModule = typeof import('node:diagnostics_channel');\n\nlet cached: DiagnosticsChannelModule | null | undefined;\n\nfunction loadDiagnosticsChannel(): DiagnosticsChannelModule | undefined {\n if (cached !== undefined) return cached ?? undefined;\n cached =\n safeRequire<DiagnosticsChannelModule>('node:diagnostics_channel') ?? null;\n return cached ?? undefined;\n}\n\n/** Whether Node's `diagnostics_channel` is available in this runtime. */\nexport function diagnosticsChannelAvailable(): boolean {\n return loadDiagnosticsChannel() !== undefined;\n}\n\n/** Handler for a plain named channel. */\nexport type ChannelMessageHandler = (\n message: unknown,\n name: string | symbol,\n) => void;\n\n/**\n * Subscribe to a named diagnostics channel. Returns an idempotent unsubscribe\n * function; a no-op (that still returns a disposer) on unsupported runtimes.\n */\nexport function subscribeChannel(\n name: string,\n handler: ChannelMessageHandler,\n): () => void {\n const dc = loadDiagnosticsChannel();\n if (!dc?.subscribe) return () => {};\n dc.subscribe(name, handler);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n dc.unsubscribe?.(name, handler);\n };\n}\n\n/** Subscriber set for a {@link https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel TracingChannel}. */\nexport interface TracingChannelHandlers {\n start?(message: unknown): void;\n end?(message: unknown): void;\n asyncStart?(message: unknown): void;\n asyncEnd?(message: unknown): void;\n error?(message: unknown): void;\n}\n\n/**\n * Subscribe to a `tracingChannel` (the `tracing:${name}:{start,end,…}` set).\n * Returns an idempotent unsubscribe; a no-op on runtimes without\n * `tracingChannel` support.\n */\nexport function subscribeTracingChannel(\n name: string,\n handlers: TracingChannelHandlers,\n): () => void {\n const dc = loadDiagnosticsChannel();\n const channel = dc?.tracingChannel?.(name);\n if (!channel) return () => {};\n // Node's typings want all five handlers; we pass the subset provided.\n channel.subscribe(handlers as Parameters<typeof channel.subscribe>[0]);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n channel.unsubscribe(handlers as Parameters<typeof channel.unsubscribe>[0]);\n };\n}\n","/**\n * Capture `console.*` calls as wide events — without monkey-patching `console`.\n *\n * Node publishes every `console.log` / `info` / `debug` / `warn` / `error` call\n * on a built-in diagnostics channel. {@link captureConsole} subscribes to those\n * channels and turns each call into an OpenTelemetry **log record** (correlated\n * to the active span via trace context by the logs SDK) and/or a **span event**\n * on the active span. Nothing patches the global `console`, so there is no\n * load-order fragility and no interference with other tooling.\n *\n * Opt-in. Call once after `init()` and keep the returned disposer to stop:\n *\n * ```ts\n * import { captureConsole } from 'autotel/diagnostics';\n *\n * const stop = captureConsole(); // every console.* → correlated log record\n * // …later: stop();\n * ```\n *\n * The built-in `console.*` channels are a Stability-1 (experimental) Node API;\n * this module degrades to a no-op where they are unavailable.\n */\n\nimport { trace, type Attributes } from '@opentelemetry/api';\nimport { logs, SeverityNumber, type Logger } from '@opentelemetry/api-logs';\nimport { safeRequire } from '../node-require.js';\nimport { subscribeChannel } from './channel.js';\n\n/** Console methods that publish a diagnostics channel. */\nexport type ConsoleLevel = 'log' | 'info' | 'debug' | 'warn' | 'error';\n\nconst ALL_LEVELS: readonly ConsoleLevel[] = [\n 'log',\n 'info',\n 'debug',\n 'warn',\n 'error',\n];\n\nconst SEVERITY: Record<ConsoleLevel, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n log: SeverityNumber.INFO,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n};\n\nexport interface CaptureConsoleOptions {\n /** Which console methods to capture. Defaults to all five. */\n levels?: readonly ConsoleLevel[];\n /**\n * Where to record captured output:\n * - `'log'` (default): emit an OpenTelemetry log record;\n * - `'span-event'`: add an event to the active span (nothing if no active span);\n * - `'both'`.\n */\n target?: 'log' | 'span-event' | 'both';\n /** Logger name for emitted records. Defaults to `'autotel.console'`. */\n loggerName?: string;\n /** Static attributes merged onto every captured record/event. */\n attributes?: Attributes;\n}\n\ntype ConsoleMessage = { args?: unknown[] };\n\n/**\n * Node publishes `console.*` channel messages as the raw argument array\n * (e.g. `console.warn('a', 1)` → `['a', 1]`); some publishers use the\n * `{ args: [...] }` object shape instead. Accept both.\n */\nfunction messageArgs(message: unknown): unknown[] {\n if (Array.isArray(message)) return message;\n return (message as ConsoleMessage)?.args ?? [];\n}\n\nconst nodeUtil = safeRequire<typeof import('node:util')>('node:util');\n\n/** Format console arguments the way `console` itself would (printf + inspect). */\nfunction formatArgs(args: unknown[]): string {\n if (nodeUtil?.format) return nodeUtil.format(...args);\n return args\n .map((a) => (typeof a === 'string' ? a : safeStringify(a)))\n .join(' ');\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Start capturing `console.*` calls as wide events. Returns a disposer that\n * stops capture. Safe to call on runtimes without the console channels (no-op).\n */\nexport function captureConsole(\n options: CaptureConsoleOptions = {},\n): () => void {\n const levels = options.levels ?? ALL_LEVELS;\n const target = options.target ?? 'log';\n const toLog = target === 'log' || target === 'both';\n const toSpan = target === 'span-event' || target === 'both';\n const logger: Logger = logs.getLogger(\n options.loggerName ?? 'autotel.console',\n );\n\n // Guard against re-entrancy: if recording a captured call itself triggers a\n // `console.*` (e.g. an exporter logging a warning), don't capture that.\n let recording = false;\n\n const disposers = levels.map((level) =>\n subscribeChannel(`console.${level}`, (message) => {\n if (recording) return;\n const args = messageArgs(message);\n const body = formatArgs(args);\n recording = true;\n try {\n const attributes: Attributes = {\n 'log.source': 'console',\n 'log.method': level,\n ...options.attributes,\n };\n if (toLog) {\n logger.emit({\n severityNumber: SEVERITY[level],\n severityText: level.toUpperCase(),\n body,\n attributes,\n });\n }\n if (toSpan) {\n trace\n .getActiveSpan()\n ?.addEvent('log', { 'log.message': body, ...attributes });\n }\n } finally {\n recording = false;\n }\n }),\n );\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n","/**\n * Lightweight HTTP spans via Node's built-in `diagnostics_channel` — no\n * monkey-patching, no `import-in-the-middle`.\n *\n * Node publishes `http.server.request.start` / `http.server.response.finish`\n * and `http.client.request.start` / `http.client.response.finish` /\n * `http.client.request.error`. {@link instrumentHttp} subscribes to those and\n * emits a `SERVER` span per inbound request (parented to an incoming W3C\n * `traceparent`) and a `CLIENT` span per outbound request (whose context it\n * injects into the outgoing headers for downstream propagation).\n *\n * ```ts\n * import { instrumentHttp } from 'autotel/diagnostics';\n *\n * const stop = instrumentHttp();\n * ```\n *\n * Scope & limitation. This is an opt-in, low-overhead alternative to\n * `@opentelemetry/instrumentation-http` for HTTP span coverage + W3C\n * propagation. Client-side propagation works (the `traceparent` is injected on\n * the `ClientRequest` object directly). What it does **not** do is establish an\n * *ambient* OpenTelemetry context for the duration of a server request handler,\n * so application spans created inside a handler will not become children of the\n * `SERVER` span.\n *\n * This is structural, not a \"wait for a newer Node\" gap. Node publishes the\n * `http.*` channels with a plain `channel.publish()` — not `runStores` /\n * `tracingChannel` — so a subscriber has no scope to bind a store to. The only\n * ways to get handler nesting both defeat the purpose of using a channel:\n * 1. `AsyncLocalStorage.enterWith()` in the start handler — no scoped exit, so\n * context leaks across requests sharing an event-loop tick / keep-alive\n * connection and misattributes spans. Strictly worse than no nesting.\n * 2. Patching `http.Server.prototype.emit` to wrap the `'request'` listener in\n * `context.with()` — monkey-patching, i.e. reimplementing\n * `@opentelemetry/instrumentation-http`.\n * If you need handler nesting, use `@opentelemetry/instrumentation-http`.\n *\n * The `http.*` channels are a Stability-1 (experimental) Node API; this module\n * degrades to a no-op where they are unavailable.\n */\n\nimport type { ClientRequest, IncomingMessage, ServerResponse } from 'node:http';\nimport {\n context as otelContext,\n defaultTextMapGetter,\n defaultTextMapSetter,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n type Attributes,\n type Span,\n type Tracer,\n} from '@opentelemetry/api';\nimport {\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_NETWORK_PROTOCOL_VERSION,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n ATTR_URL_FULL,\n ATTR_URL_PATH,\n ATTR_URL_SCHEME,\n ATTR_USER_AGENT_ORIGINAL,\n} from '@opentelemetry/semantic-conventions';\nimport { subscribeChannel } from './channel.js';\n\nexport interface InstrumentHttpOptions {\n /** Instrument inbound (server) requests. Default `true`. */\n server?: boolean;\n /** Instrument outbound (client) requests. Default `true`. */\n client?: boolean;\n /** Tracer to use. Defaults to `trace.getTracer('autotel.http-diagnostics')`. */\n tracer?: Tracer;\n}\n\ninterface ServerStartMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ServerFinishMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ClientStartMessage {\n request?: ClientRequest;\n}\ninterface ClientFinishMessage {\n request?: ClientRequest;\n response?: IncomingMessage;\n}\ninterface ClientErrorMessage {\n request?: ClientRequest;\n error?: unknown;\n}\n\nconst SERVER_SPANS = new WeakMap<object, Span>();\nconst CLIENT_SPANS = new WeakMap<object, Span>();\n\nfunction firstHeader(value: string | string[] | undefined): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction splitHostPort(host: string | undefined): {\n address?: string;\n port?: number;\n} {\n if (!host) return {};\n const idx = host.lastIndexOf(':');\n if (idx === -1) return { address: host };\n const port = Number(host.slice(idx + 1));\n return {\n address: host.slice(0, idx),\n port: Number.isFinite(port) ? port : undefined,\n };\n}\n\n/**\n * Start emitting HTTP server/client spans from Node's HTTP diagnostics\n * channels. Returns a disposer; a no-op on runtimes without the channels.\n */\nexport function instrumentHttp(\n options: InstrumentHttpOptions = {},\n): () => void {\n const tracer = options.tracer ?? trace.getTracer('autotel.http-diagnostics');\n const disposers: Array<() => void> = [];\n\n if (options.server !== false) {\n disposers.push(\n subscribeChannel('http.server.request.start', (message) => {\n const request = (message as ServerStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n const host = firstHeader(request.headers.host);\n const { address, port } = splitHostPort(host);\n const path = (request.url ?? '/').split('?', 1)[0];\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_URL_PATH]: path,\n [ATTR_URL_SCHEME]: 'http',\n [ATTR_NETWORK_PROTOCOL_VERSION]: request.httpVersion,\n [ATTR_USER_AGENT_ORIGINAL]: firstHeader(\n request.headers['user-agent'],\n ),\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n };\n const parent = propagation.extract(\n otelContext.active(),\n request.headers,\n defaultTextMapGetter,\n );\n const span = tracer.startSpan(\n method,\n { kind: SpanKind.SERVER, attributes },\n parent,\n );\n SERVER_SPANS.set(request, span);\n }),\n subscribeChannel('http.server.response.finish', (message) => {\n const { request, response } = (message as ServerFinishMessage) ?? {};\n if (!request) return;\n const span = SERVER_SPANS.get(request);\n if (!span) return;\n SERVER_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 500);\n }),\n );\n }\n\n if (options.client !== false) {\n disposers.push(\n subscribeChannel('http.client.request.start', (message) => {\n const request = (message as ClientStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n // `ClientRequest` exposes host/protocol/path on the public surface.\n const req = request as ClientRequest & {\n host?: string;\n protocol?: string;\n path?: string;\n };\n const { address, port } = splitHostPort(req.host);\n const scheme = (req.protocol ?? 'http:').replace(':', '');\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n [ATTR_URL_FULL]:\n address && req.path\n ? `${scheme}://${req.host}${req.path}`\n : undefined,\n };\n const span = tracer.startSpan(method, {\n kind: SpanKind.CLIENT,\n attributes,\n });\n CLIENT_SPANS.set(request, span);\n\n // Inject this span's context into the outbound headers so the\n // downstream service continues the trace.\n if (!request.headersSent) {\n const carrier: Record<string, string> = {};\n propagation.inject(\n trace.setSpan(otelContext.active(), span),\n carrier,\n defaultTextMapSetter,\n );\n for (const [key, value] of Object.entries(carrier)) {\n try {\n request.setHeader(key, value);\n } catch {\n // Headers already sent / immutable — propagation best-effort.\n }\n }\n }\n }),\n subscribeChannel('http.client.response.finish', (message) => {\n const { request, response } = (message as ClientFinishMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 400);\n }),\n subscribeChannel('http.client.request.error', (message) => {\n const { request, error } = (message as ClientErrorMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n if (error instanceof Error) span.recordException(error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : undefined,\n });\n span.end();\n }),\n );\n }\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n\n/** Set status code + error status (when `>= errorAt`) and end the span. */\nfunction finishHttpSpan(\n span: Span,\n statusCode: number | undefined,\n errorAt: number,\n): void {\n if (statusCode !== undefined) {\n span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, statusCode);\n if (statusCode >= errorAt) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n }\n span.end();\n}\n"],"mappings":"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"}
|
package/dist/diagnostics.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.d.cts","names":[],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"diagnostics.d.cts","names":[],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBA8BgB;;KAKJ,yBACV,kBACA;;;;;iBAOc,iBACd,cACA,SAAS;;UAcM;EACf,OAAO;EACP,KAAK;EACL,YAAY;EACZ,UAAU;EACV,OAAO;;;;;;;iBAQO,wBACd,cACA,UAAU;;;;KC9CA;UAkBK;;EAEf,kBAAkB;;;;;;;EAOlB;;EAEA;;EAEA,aAAa;;;;;;iBAqCC,eACd,UAAS;;;UC/BM;;EAEf;;EAEA;;EAEA,SAAS;;;;;;iBAgDK,eACd,UAAS"}
|
package/dist/diagnostics.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.d.ts","names":[],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","names":[],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBA8BgB;;KAKJ,yBACV,kBACA;;;;;iBAOc,iBACd,cACA,SAAS;;UAcM;EACf,OAAO;EACP,KAAK;EACL,YAAY;EACZ,UAAU;EACV,OAAO;;;;;;;iBAQO,wBACd,cACA,UAAU;;;;KC9CA;UAkBK;;EAEf,kBAAkB;;;;;;;EAOlB;;EAEA;;EAEA,aAAa;;;;;;iBAqCC,eACd,UAAS;;;UC/BM;;EAEf;;EAEA;;EAEA,SAAS;;;;;;iBAgDK,eACd,UAAS"}
|
package/dist/diagnostics.js
CHANGED
|
@@ -99,6 +99,15 @@ const SEVERITY = {
|
|
|
99
99
|
warn: SeverityNumber.WARN,
|
|
100
100
|
error: SeverityNumber.ERROR
|
|
101
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* Node publishes `console.*` channel messages as the raw argument array
|
|
104
|
+
* (e.g. `console.warn('a', 1)` → `['a', 1]`); some publishers use the
|
|
105
|
+
* `{ args: [...] }` object shape instead. Accept both.
|
|
106
|
+
*/
|
|
107
|
+
function messageArgs(message) {
|
|
108
|
+
if (Array.isArray(message)) return message;
|
|
109
|
+
return message?.args ?? [];
|
|
110
|
+
}
|
|
102
111
|
const nodeUtil = safeRequire("node:util");
|
|
103
112
|
/** Format console arguments the way `console` itself would (printf + inspect). */
|
|
104
113
|
function formatArgs(args) {
|
|
@@ -125,7 +134,7 @@ function captureConsole(options = {}) {
|
|
|
125
134
|
let recording = false;
|
|
126
135
|
const disposers = levels.map((level) => subscribeChannel(`console.${level}`, (message) => {
|
|
127
136
|
if (recording) return;
|
|
128
|
-
const body = formatArgs(message
|
|
137
|
+
const body = formatArgs(messageArgs(message));
|
|
129
138
|
recording = true;
|
|
130
139
|
try {
|
|
131
140
|
const attributes = {
|
package/dist/diagnostics.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.js","names":["otelContext"],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"sourcesContent":["/**\n * Edge-safe wrappers over Node's `diagnostics_channel`.\n *\n * The module is loaded lazily through {@link safeRequire} — never a static\n * `node:` import — so merely importing this file is side-effect-free and bundles\n * cleanly for browser/edge targets, where every subscribe call degrades to a\n * no-op (returning an unsubscribe that does nothing). This is the shared\n * primitive behind autotel's diagnostics-channel integrations (console capture,\n * HTTP spans) and any app- or library-specific channel you want to bridge into\n * a span/event.\n *\n * `diagnostics_channel.subscribe` (Node 18.7+) and `tracingChannel` (Node 19+)\n * are used; autotel targets Node 22+, but on any runtime that lacks them the\n * loader returns `undefined` and the helpers no-op.\n */\n\nimport { safeRequire } from '../node-require.js';\n\ntype DiagnosticsChannelModule = typeof import('node:diagnostics_channel');\n\nlet cached: DiagnosticsChannelModule | null | undefined;\n\nfunction loadDiagnosticsChannel(): DiagnosticsChannelModule | undefined {\n if (cached !== undefined) return cached ?? undefined;\n cached =\n safeRequire<DiagnosticsChannelModule>('node:diagnostics_channel') ?? null;\n return cached ?? undefined;\n}\n\n/** Whether Node's `diagnostics_channel` is available in this runtime. */\nexport function diagnosticsChannelAvailable(): boolean {\n return loadDiagnosticsChannel() !== undefined;\n}\n\n/** Handler for a plain named channel. */\nexport type ChannelMessageHandler = (\n message: unknown,\n name: string | symbol,\n) => void;\n\n/**\n * Subscribe to a named diagnostics channel. Returns an idempotent unsubscribe\n * function; a no-op (that still returns a disposer) on unsupported runtimes.\n */\nexport function subscribeChannel(\n name: string,\n handler: ChannelMessageHandler,\n): () => void {\n const dc = loadDiagnosticsChannel();\n if (!dc?.subscribe) return () => {};\n dc.subscribe(name, handler);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n dc.unsubscribe?.(name, handler);\n };\n}\n\n/** Subscriber set for a {@link https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel TracingChannel}. */\nexport interface TracingChannelHandlers {\n start?(message: unknown): void;\n end?(message: unknown): void;\n asyncStart?(message: unknown): void;\n asyncEnd?(message: unknown): void;\n error?(message: unknown): void;\n}\n\n/**\n * Subscribe to a `tracingChannel` (the `tracing:${name}:{start,end,…}` set).\n * Returns an idempotent unsubscribe; a no-op on runtimes without\n * `tracingChannel` support.\n */\nexport function subscribeTracingChannel(\n name: string,\n handlers: TracingChannelHandlers,\n): () => void {\n const dc = loadDiagnosticsChannel();\n const channel = dc?.tracingChannel?.(name);\n if (!channel) return () => {};\n // Node's typings want all five handlers; we pass the subset provided.\n channel.subscribe(handlers as Parameters<typeof channel.subscribe>[0]);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n channel.unsubscribe(handlers as Parameters<typeof channel.unsubscribe>[0]);\n };\n}\n","/**\n * Capture `console.*` calls as wide events — without monkey-patching `console`.\n *\n * Node publishes every `console.log` / `info` / `debug` / `warn` / `error` call\n * on a built-in diagnostics channel. {@link captureConsole} subscribes to those\n * channels and turns each call into an OpenTelemetry **log record** (correlated\n * to the active span via trace context by the logs SDK) and/or a **span event**\n * on the active span. Nothing patches the global `console`, so there is no\n * load-order fragility and no interference with other tooling.\n *\n * Opt-in. Call once after `init()` and keep the returned disposer to stop:\n *\n * ```ts\n * import { captureConsole } from 'autotel/diagnostics';\n *\n * const stop = captureConsole(); // every console.* → correlated log record\n * // …later: stop();\n * ```\n *\n * The built-in `console.*` channels are a Stability-1 (experimental) Node API;\n * this module degrades to a no-op where they are unavailable.\n */\n\nimport { trace, type Attributes } from '@opentelemetry/api';\nimport { logs, SeverityNumber, type Logger } from '@opentelemetry/api-logs';\nimport { safeRequire } from '../node-require.js';\nimport { subscribeChannel } from './channel.js';\n\n/** Console methods that publish a diagnostics channel. */\nexport type ConsoleLevel = 'log' | 'info' | 'debug' | 'warn' | 'error';\n\nconst ALL_LEVELS: readonly ConsoleLevel[] = [\n 'log',\n 'info',\n 'debug',\n 'warn',\n 'error',\n];\n\nconst SEVERITY: Record<ConsoleLevel, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n log: SeverityNumber.INFO,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n};\n\nexport interface CaptureConsoleOptions {\n /** Which console methods to capture. Defaults to all five. */\n levels?: readonly ConsoleLevel[];\n /**\n * Where to record captured output:\n * - `'log'` (default): emit an OpenTelemetry log record;\n * - `'span-event'`: add an event to the active span (nothing if no active span);\n * - `'both'`.\n */\n target?: 'log' | 'span-event' | 'both';\n /** Logger name for emitted records. Defaults to `'autotel.console'`. */\n loggerName?: string;\n /** Static attributes merged onto every captured record/event. */\n attributes?: Attributes;\n}\n\ntype ConsoleMessage = { args?: unknown[] };\n\nconst nodeUtil = safeRequire<typeof import('node:util')>('node:util');\n\n/** Format console arguments the way `console` itself would (printf + inspect). */\nfunction formatArgs(args: unknown[]): string {\n if (nodeUtil?.format) return nodeUtil.format(...args);\n return args\n .map((a) => (typeof a === 'string' ? a : safeStringify(a)))\n .join(' ');\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Start capturing `console.*` calls as wide events. Returns a disposer that\n * stops capture. Safe to call on runtimes without the console channels (no-op).\n */\nexport function captureConsole(\n options: CaptureConsoleOptions = {},\n): () => void {\n const levels = options.levels ?? ALL_LEVELS;\n const target = options.target ?? 'log';\n const toLog = target === 'log' || target === 'both';\n const toSpan = target === 'span-event' || target === 'both';\n const logger: Logger = logs.getLogger(\n options.loggerName ?? 'autotel.console',\n );\n\n // Guard against re-entrancy: if recording a captured call itself triggers a\n // `console.*` (e.g. an exporter logging a warning), don't capture that.\n let recording = false;\n\n const disposers = levels.map((level) =>\n subscribeChannel(`console.${level}`, (message) => {\n if (recording) return;\n const args = (message as ConsoleMessage)?.args ?? [];\n const body = formatArgs(args as unknown[]);\n recording = true;\n try {\n const attributes: Attributes = {\n 'log.source': 'console',\n 'log.method': level,\n ...options.attributes,\n };\n if (toLog) {\n logger.emit({\n severityNumber: SEVERITY[level],\n severityText: level.toUpperCase(),\n body,\n attributes,\n });\n }\n if (toSpan) {\n trace\n .getActiveSpan()\n ?.addEvent('log', { 'log.message': body, ...attributes });\n }\n } finally {\n recording = false;\n }\n }),\n );\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n","/**\n * Lightweight HTTP spans via Node's built-in `diagnostics_channel` — no\n * monkey-patching, no `import-in-the-middle`.\n *\n * Node publishes `http.server.request.start` / `http.server.response.finish`\n * and `http.client.request.start` / `http.client.response.finish` /\n * `http.client.request.error`. {@link instrumentHttp} subscribes to those and\n * emits a `SERVER` span per inbound request (parented to an incoming W3C\n * `traceparent`) and a `CLIENT` span per outbound request (whose context it\n * injects into the outgoing headers for downstream propagation).\n *\n * ```ts\n * import { instrumentHttp } from 'autotel/diagnostics';\n *\n * const stop = instrumentHttp();\n * ```\n *\n * Scope & limitation. This is an opt-in, low-overhead alternative to\n * `@opentelemetry/instrumentation-http` for HTTP span coverage + W3C\n * propagation. Client-side propagation works (the `traceparent` is injected on\n * the `ClientRequest` object directly). What it does **not** do is establish an\n * *ambient* OpenTelemetry context for the duration of a server request handler,\n * so application spans created inside a handler will not become children of the\n * `SERVER` span.\n *\n * This is structural, not a \"wait for a newer Node\" gap. Node publishes the\n * `http.*` channels with a plain `channel.publish()` — not `runStores` /\n * `tracingChannel` — so a subscriber has no scope to bind a store to. The only\n * ways to get handler nesting both defeat the purpose of using a channel:\n * 1. `AsyncLocalStorage.enterWith()` in the start handler — no scoped exit, so\n * context leaks across requests sharing an event-loop tick / keep-alive\n * connection and misattributes spans. Strictly worse than no nesting.\n * 2. Patching `http.Server.prototype.emit` to wrap the `'request'` listener in\n * `context.with()` — monkey-patching, i.e. reimplementing\n * `@opentelemetry/instrumentation-http`.\n * If you need handler nesting, use `@opentelemetry/instrumentation-http`.\n *\n * The `http.*` channels are a Stability-1 (experimental) Node API; this module\n * degrades to a no-op where they are unavailable.\n */\n\nimport type { ClientRequest, IncomingMessage, ServerResponse } from 'node:http';\nimport {\n context as otelContext,\n defaultTextMapGetter,\n defaultTextMapSetter,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n type Attributes,\n type Span,\n type Tracer,\n} from '@opentelemetry/api';\nimport {\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_NETWORK_PROTOCOL_VERSION,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n ATTR_URL_FULL,\n ATTR_URL_PATH,\n ATTR_URL_SCHEME,\n ATTR_USER_AGENT_ORIGINAL,\n} from '@opentelemetry/semantic-conventions';\nimport { subscribeChannel } from './channel.js';\n\nexport interface InstrumentHttpOptions {\n /** Instrument inbound (server) requests. Default `true`. */\n server?: boolean;\n /** Instrument outbound (client) requests. Default `true`. */\n client?: boolean;\n /** Tracer to use. Defaults to `trace.getTracer('autotel.http-diagnostics')`. */\n tracer?: Tracer;\n}\n\ninterface ServerStartMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ServerFinishMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ClientStartMessage {\n request?: ClientRequest;\n}\ninterface ClientFinishMessage {\n request?: ClientRequest;\n response?: IncomingMessage;\n}\ninterface ClientErrorMessage {\n request?: ClientRequest;\n error?: unknown;\n}\n\nconst SERVER_SPANS = new WeakMap<object, Span>();\nconst CLIENT_SPANS = new WeakMap<object, Span>();\n\nfunction firstHeader(value: string | string[] | undefined): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction splitHostPort(host: string | undefined): {\n address?: string;\n port?: number;\n} {\n if (!host) return {};\n const idx = host.lastIndexOf(':');\n if (idx === -1) return { address: host };\n const port = Number(host.slice(idx + 1));\n return {\n address: host.slice(0, idx),\n port: Number.isFinite(port) ? port : undefined,\n };\n}\n\n/**\n * Start emitting HTTP server/client spans from Node's HTTP diagnostics\n * channels. Returns a disposer; a no-op on runtimes without the channels.\n */\nexport function instrumentHttp(\n options: InstrumentHttpOptions = {},\n): () => void {\n const tracer = options.tracer ?? trace.getTracer('autotel.http-diagnostics');\n const disposers: Array<() => void> = [];\n\n if (options.server !== false) {\n disposers.push(\n subscribeChannel('http.server.request.start', (message) => {\n const request = (message as ServerStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n const host = firstHeader(request.headers.host);\n const { address, port } = splitHostPort(host);\n const path = (request.url ?? '/').split('?', 1)[0];\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_URL_PATH]: path,\n [ATTR_URL_SCHEME]: 'http',\n [ATTR_NETWORK_PROTOCOL_VERSION]: request.httpVersion,\n [ATTR_USER_AGENT_ORIGINAL]: firstHeader(\n request.headers['user-agent'],\n ),\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n };\n const parent = propagation.extract(\n otelContext.active(),\n request.headers,\n defaultTextMapGetter,\n );\n const span = tracer.startSpan(\n method,\n { kind: SpanKind.SERVER, attributes },\n parent,\n );\n SERVER_SPANS.set(request, span);\n }),\n subscribeChannel('http.server.response.finish', (message) => {\n const { request, response } = (message as ServerFinishMessage) ?? {};\n if (!request) return;\n const span = SERVER_SPANS.get(request);\n if (!span) return;\n SERVER_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 500);\n }),\n );\n }\n\n if (options.client !== false) {\n disposers.push(\n subscribeChannel('http.client.request.start', (message) => {\n const request = (message as ClientStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n // `ClientRequest` exposes host/protocol/path on the public surface.\n const req = request as ClientRequest & {\n host?: string;\n protocol?: string;\n path?: string;\n };\n const { address, port } = splitHostPort(req.host);\n const scheme = (req.protocol ?? 'http:').replace(':', '');\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n [ATTR_URL_FULL]:\n address && req.path\n ? `${scheme}://${req.host}${req.path}`\n : undefined,\n };\n const span = tracer.startSpan(method, {\n kind: SpanKind.CLIENT,\n attributes,\n });\n CLIENT_SPANS.set(request, span);\n\n // Inject this span's context into the outbound headers so the\n // downstream service continues the trace.\n if (!request.headersSent) {\n const carrier: Record<string, string> = {};\n propagation.inject(\n trace.setSpan(otelContext.active(), span),\n carrier,\n defaultTextMapSetter,\n );\n for (const [key, value] of Object.entries(carrier)) {\n try {\n request.setHeader(key, value);\n } catch {\n // Headers already sent / immutable — propagation best-effort.\n }\n }\n }\n }),\n subscribeChannel('http.client.response.finish', (message) => {\n const { request, response } = (message as ClientFinishMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 400);\n }),\n subscribeChannel('http.client.request.error', (message) => {\n const { request, error } = (message as ClientErrorMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n if (error instanceof Error) span.recordException(error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : undefined,\n });\n span.end();\n }),\n );\n }\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n\n/** Set status code + error status (when `>= errorAt`) and end the span. */\nfunction finishHttpSpan(\n span: Span,\n statusCode: number | undefined,\n errorAt: number,\n): void {\n if (statusCode !== undefined) {\n span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, statusCode);\n if (statusCode >= errorAt) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n }\n span.end();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"diagnostics.js","names":["otelContext"],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"sourcesContent":["/**\n * Edge-safe wrappers over Node's `diagnostics_channel`.\n *\n * The module is loaded lazily through {@link safeRequire} — never a static\n * `node:` import — so merely importing this file is side-effect-free and bundles\n * cleanly for browser/edge targets, where every subscribe call degrades to a\n * no-op (returning an unsubscribe that does nothing). This is the shared\n * primitive behind autotel's diagnostics-channel integrations (console capture,\n * HTTP spans) and any app- or library-specific channel you want to bridge into\n * a span/event.\n *\n * `diagnostics_channel.subscribe` (Node 18.7+) and `tracingChannel` (Node 19+)\n * are used; autotel targets Node 22+, but on any runtime that lacks them the\n * loader returns `undefined` and the helpers no-op.\n */\n\nimport { safeRequire } from '../node-require.js';\n\ntype DiagnosticsChannelModule = typeof import('node:diagnostics_channel');\n\nlet cached: DiagnosticsChannelModule | null | undefined;\n\nfunction loadDiagnosticsChannel(): DiagnosticsChannelModule | undefined {\n if (cached !== undefined) return cached ?? undefined;\n cached =\n safeRequire<DiagnosticsChannelModule>('node:diagnostics_channel') ?? null;\n return cached ?? undefined;\n}\n\n/** Whether Node's `diagnostics_channel` is available in this runtime. */\nexport function diagnosticsChannelAvailable(): boolean {\n return loadDiagnosticsChannel() !== undefined;\n}\n\n/** Handler for a plain named channel. */\nexport type ChannelMessageHandler = (\n message: unknown,\n name: string | symbol,\n) => void;\n\n/**\n * Subscribe to a named diagnostics channel. Returns an idempotent unsubscribe\n * function; a no-op (that still returns a disposer) on unsupported runtimes.\n */\nexport function subscribeChannel(\n name: string,\n handler: ChannelMessageHandler,\n): () => void {\n const dc = loadDiagnosticsChannel();\n if (!dc?.subscribe) return () => {};\n dc.subscribe(name, handler);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n dc.unsubscribe?.(name, handler);\n };\n}\n\n/** Subscriber set for a {@link https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel TracingChannel}. */\nexport interface TracingChannelHandlers {\n start?(message: unknown): void;\n end?(message: unknown): void;\n asyncStart?(message: unknown): void;\n asyncEnd?(message: unknown): void;\n error?(message: unknown): void;\n}\n\n/**\n * Subscribe to a `tracingChannel` (the `tracing:${name}:{start,end,…}` set).\n * Returns an idempotent unsubscribe; a no-op on runtimes without\n * `tracingChannel` support.\n */\nexport function subscribeTracingChannel(\n name: string,\n handlers: TracingChannelHandlers,\n): () => void {\n const dc = loadDiagnosticsChannel();\n const channel = dc?.tracingChannel?.(name);\n if (!channel) return () => {};\n // Node's typings want all five handlers; we pass the subset provided.\n channel.subscribe(handlers as Parameters<typeof channel.subscribe>[0]);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n channel.unsubscribe(handlers as Parameters<typeof channel.unsubscribe>[0]);\n };\n}\n","/**\n * Capture `console.*` calls as wide events — without monkey-patching `console`.\n *\n * Node publishes every `console.log` / `info` / `debug` / `warn` / `error` call\n * on a built-in diagnostics channel. {@link captureConsole} subscribes to those\n * channels and turns each call into an OpenTelemetry **log record** (correlated\n * to the active span via trace context by the logs SDK) and/or a **span event**\n * on the active span. Nothing patches the global `console`, so there is no\n * load-order fragility and no interference with other tooling.\n *\n * Opt-in. Call once after `init()` and keep the returned disposer to stop:\n *\n * ```ts\n * import { captureConsole } from 'autotel/diagnostics';\n *\n * const stop = captureConsole(); // every console.* → correlated log record\n * // …later: stop();\n * ```\n *\n * The built-in `console.*` channels are a Stability-1 (experimental) Node API;\n * this module degrades to a no-op where they are unavailable.\n */\n\nimport { trace, type Attributes } from '@opentelemetry/api';\nimport { logs, SeverityNumber, type Logger } from '@opentelemetry/api-logs';\nimport { safeRequire } from '../node-require.js';\nimport { subscribeChannel } from './channel.js';\n\n/** Console methods that publish a diagnostics channel. */\nexport type ConsoleLevel = 'log' | 'info' | 'debug' | 'warn' | 'error';\n\nconst ALL_LEVELS: readonly ConsoleLevel[] = [\n 'log',\n 'info',\n 'debug',\n 'warn',\n 'error',\n];\n\nconst SEVERITY: Record<ConsoleLevel, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n log: SeverityNumber.INFO,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n};\n\nexport interface CaptureConsoleOptions {\n /** Which console methods to capture. Defaults to all five. */\n levels?: readonly ConsoleLevel[];\n /**\n * Where to record captured output:\n * - `'log'` (default): emit an OpenTelemetry log record;\n * - `'span-event'`: add an event to the active span (nothing if no active span);\n * - `'both'`.\n */\n target?: 'log' | 'span-event' | 'both';\n /** Logger name for emitted records. Defaults to `'autotel.console'`. */\n loggerName?: string;\n /** Static attributes merged onto every captured record/event. */\n attributes?: Attributes;\n}\n\ntype ConsoleMessage = { args?: unknown[] };\n\n/**\n * Node publishes `console.*` channel messages as the raw argument array\n * (e.g. `console.warn('a', 1)` → `['a', 1]`); some publishers use the\n * `{ args: [...] }` object shape instead. Accept both.\n */\nfunction messageArgs(message: unknown): unknown[] {\n if (Array.isArray(message)) return message;\n return (message as ConsoleMessage)?.args ?? [];\n}\n\nconst nodeUtil = safeRequire<typeof import('node:util')>('node:util');\n\n/** Format console arguments the way `console` itself would (printf + inspect). */\nfunction formatArgs(args: unknown[]): string {\n if (nodeUtil?.format) return nodeUtil.format(...args);\n return args\n .map((a) => (typeof a === 'string' ? a : safeStringify(a)))\n .join(' ');\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Start capturing `console.*` calls as wide events. Returns a disposer that\n * stops capture. Safe to call on runtimes without the console channels (no-op).\n */\nexport function captureConsole(\n options: CaptureConsoleOptions = {},\n): () => void {\n const levels = options.levels ?? ALL_LEVELS;\n const target = options.target ?? 'log';\n const toLog = target === 'log' || target === 'both';\n const toSpan = target === 'span-event' || target === 'both';\n const logger: Logger = logs.getLogger(\n options.loggerName ?? 'autotel.console',\n );\n\n // Guard against re-entrancy: if recording a captured call itself triggers a\n // `console.*` (e.g. an exporter logging a warning), don't capture that.\n let recording = false;\n\n const disposers = levels.map((level) =>\n subscribeChannel(`console.${level}`, (message) => {\n if (recording) return;\n const args = messageArgs(message);\n const body = formatArgs(args);\n recording = true;\n try {\n const attributes: Attributes = {\n 'log.source': 'console',\n 'log.method': level,\n ...options.attributes,\n };\n if (toLog) {\n logger.emit({\n severityNumber: SEVERITY[level],\n severityText: level.toUpperCase(),\n body,\n attributes,\n });\n }\n if (toSpan) {\n trace\n .getActiveSpan()\n ?.addEvent('log', { 'log.message': body, ...attributes });\n }\n } finally {\n recording = false;\n }\n }),\n );\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n","/**\n * Lightweight HTTP spans via Node's built-in `diagnostics_channel` — no\n * monkey-patching, no `import-in-the-middle`.\n *\n * Node publishes `http.server.request.start` / `http.server.response.finish`\n * and `http.client.request.start` / `http.client.response.finish` /\n * `http.client.request.error`. {@link instrumentHttp} subscribes to those and\n * emits a `SERVER` span per inbound request (parented to an incoming W3C\n * `traceparent`) and a `CLIENT` span per outbound request (whose context it\n * injects into the outgoing headers for downstream propagation).\n *\n * ```ts\n * import { instrumentHttp } from 'autotel/diagnostics';\n *\n * const stop = instrumentHttp();\n * ```\n *\n * Scope & limitation. This is an opt-in, low-overhead alternative to\n * `@opentelemetry/instrumentation-http` for HTTP span coverage + W3C\n * propagation. Client-side propagation works (the `traceparent` is injected on\n * the `ClientRequest` object directly). What it does **not** do is establish an\n * *ambient* OpenTelemetry context for the duration of a server request handler,\n * so application spans created inside a handler will not become children of the\n * `SERVER` span.\n *\n * This is structural, not a \"wait for a newer Node\" gap. Node publishes the\n * `http.*` channels with a plain `channel.publish()` — not `runStores` /\n * `tracingChannel` — so a subscriber has no scope to bind a store to. The only\n * ways to get handler nesting both defeat the purpose of using a channel:\n * 1. `AsyncLocalStorage.enterWith()` in the start handler — no scoped exit, so\n * context leaks across requests sharing an event-loop tick / keep-alive\n * connection and misattributes spans. Strictly worse than no nesting.\n * 2. Patching `http.Server.prototype.emit` to wrap the `'request'` listener in\n * `context.with()` — monkey-patching, i.e. reimplementing\n * `@opentelemetry/instrumentation-http`.\n * If you need handler nesting, use `@opentelemetry/instrumentation-http`.\n *\n * The `http.*` channels are a Stability-1 (experimental) Node API; this module\n * degrades to a no-op where they are unavailable.\n */\n\nimport type { ClientRequest, IncomingMessage, ServerResponse } from 'node:http';\nimport {\n context as otelContext,\n defaultTextMapGetter,\n defaultTextMapSetter,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n type Attributes,\n type Span,\n type Tracer,\n} from '@opentelemetry/api';\nimport {\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_NETWORK_PROTOCOL_VERSION,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n ATTR_URL_FULL,\n ATTR_URL_PATH,\n ATTR_URL_SCHEME,\n ATTR_USER_AGENT_ORIGINAL,\n} from '@opentelemetry/semantic-conventions';\nimport { subscribeChannel } from './channel.js';\n\nexport interface InstrumentHttpOptions {\n /** Instrument inbound (server) requests. Default `true`. */\n server?: boolean;\n /** Instrument outbound (client) requests. Default `true`. */\n client?: boolean;\n /** Tracer to use. Defaults to `trace.getTracer('autotel.http-diagnostics')`. */\n tracer?: Tracer;\n}\n\ninterface ServerStartMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ServerFinishMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ClientStartMessage {\n request?: ClientRequest;\n}\ninterface ClientFinishMessage {\n request?: ClientRequest;\n response?: IncomingMessage;\n}\ninterface ClientErrorMessage {\n request?: ClientRequest;\n error?: unknown;\n}\n\nconst SERVER_SPANS = new WeakMap<object, Span>();\nconst CLIENT_SPANS = new WeakMap<object, Span>();\n\nfunction firstHeader(value: string | string[] | undefined): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction splitHostPort(host: string | undefined): {\n address?: string;\n port?: number;\n} {\n if (!host) return {};\n const idx = host.lastIndexOf(':');\n if (idx === -1) return { address: host };\n const port = Number(host.slice(idx + 1));\n return {\n address: host.slice(0, idx),\n port: Number.isFinite(port) ? port : undefined,\n };\n}\n\n/**\n * Start emitting HTTP server/client spans from Node's HTTP diagnostics\n * channels. Returns a disposer; a no-op on runtimes without the channels.\n */\nexport function instrumentHttp(\n options: InstrumentHttpOptions = {},\n): () => void {\n const tracer = options.tracer ?? trace.getTracer('autotel.http-diagnostics');\n const disposers: Array<() => void> = [];\n\n if (options.server !== false) {\n disposers.push(\n subscribeChannel('http.server.request.start', (message) => {\n const request = (message as ServerStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n const host = firstHeader(request.headers.host);\n const { address, port } = splitHostPort(host);\n const path = (request.url ?? '/').split('?', 1)[0];\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_URL_PATH]: path,\n [ATTR_URL_SCHEME]: 'http',\n [ATTR_NETWORK_PROTOCOL_VERSION]: request.httpVersion,\n [ATTR_USER_AGENT_ORIGINAL]: firstHeader(\n request.headers['user-agent'],\n ),\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n };\n const parent = propagation.extract(\n otelContext.active(),\n request.headers,\n defaultTextMapGetter,\n );\n const span = tracer.startSpan(\n method,\n { kind: SpanKind.SERVER, attributes },\n parent,\n );\n SERVER_SPANS.set(request, span);\n }),\n subscribeChannel('http.server.response.finish', (message) => {\n const { request, response } = (message as ServerFinishMessage) ?? {};\n if (!request) return;\n const span = SERVER_SPANS.get(request);\n if (!span) return;\n SERVER_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 500);\n }),\n );\n }\n\n if (options.client !== false) {\n disposers.push(\n subscribeChannel('http.client.request.start', (message) => {\n const request = (message as ClientStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n // `ClientRequest` exposes host/protocol/path on the public surface.\n const req = request as ClientRequest & {\n host?: string;\n protocol?: string;\n path?: string;\n };\n const { address, port } = splitHostPort(req.host);\n const scheme = (req.protocol ?? 'http:').replace(':', '');\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n [ATTR_URL_FULL]:\n address && req.path\n ? `${scheme}://${req.host}${req.path}`\n : undefined,\n };\n const span = tracer.startSpan(method, {\n kind: SpanKind.CLIENT,\n attributes,\n });\n CLIENT_SPANS.set(request, span);\n\n // Inject this span's context into the outbound headers so the\n // downstream service continues the trace.\n if (!request.headersSent) {\n const carrier: Record<string, string> = {};\n propagation.inject(\n trace.setSpan(otelContext.active(), span),\n carrier,\n defaultTextMapSetter,\n );\n for (const [key, value] of Object.entries(carrier)) {\n try {\n request.setHeader(key, value);\n } catch {\n // Headers already sent / immutable — propagation best-effort.\n }\n }\n }\n }),\n subscribeChannel('http.client.response.finish', (message) => {\n const { request, response } = (message as ClientFinishMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 400);\n }),\n subscribeChannel('http.client.request.error', (message) => {\n const { request, error } = (message as ClientErrorMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n if (error instanceof Error) span.recordException(error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : undefined,\n });\n span.end();\n }),\n );\n }\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n\n/** Set status code + error status (when `>= errorAt`) and end the span. */\nfunction finishHttpSpan(\n span: Span,\n statusCode: number | undefined,\n errorAt: number,\n): void {\n if (statusCode !== undefined) {\n span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, statusCode);\n if (statusCode >= errorAt) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n }\n span.end();\n}\n"],"mappings":"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"}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
//#region src/drain-pipeline.d.ts
|
|
2
2
|
interface DrainPipelineOptions<T = unknown> {
|
|
3
3
|
batch?: {
|
|
4
|
-
/** Maximum events per batch. @default 50 */
|
|
4
|
+
/** Maximum events per batch. @default 50 */
|
|
5
|
+
size?: number;
|
|
6
|
+
/** Max time an event can stay buffered before flush. @default 5000 */
|
|
5
7
|
intervalMs?: number;
|
|
6
8
|
};
|
|
7
9
|
retry?: {
|
|
8
|
-
/** Total attempts including first try. @default 3 */
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
/** Total attempts including first try. @default 3 */
|
|
11
|
+
maxAttempts?: number;
|
|
12
|
+
/** Delay strategy between attempts. @default 'exponential' */
|
|
13
|
+
backoff?: 'exponential' | 'linear' | 'fixed';
|
|
14
|
+
/** Base delay for first retry. @default 1000 */
|
|
15
|
+
initialDelayMs?: number;
|
|
16
|
+
/** Max delay cap. @default 30000 */
|
|
17
|
+
maxDelayMs?: number;
|
|
18
|
+
/** Add random jitter to delays. @default true */
|
|
12
19
|
jitter?: boolean;
|
|
13
20
|
};
|
|
14
21
|
/** Max buffered events before dropping. @default 1000 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drain-pipeline.d.cts","names":[],"sources":["../src/drain-pipeline.ts"],"mappings":";UAAiB,
|
|
1
|
+
{"version":3,"file":"drain-pipeline.d.cts","names":[],"sources":["../src/drain-pipeline.ts"],"mappings":";UAAiB,qBAAqB;EACpC;;IAEE;;IAEA;;EAEF;;IAEE;;IAEA;;IAEA;;IAEA;;IAEA;;;EAGF;;EAEA;;EAEA,aAAa,QAAQ,KAAK,QAAQ;;UAGnB,gBAAgB;GAC9B,KAAK;;EAEN,aAAa;;EAEb,gBAAgB;WACP;;iBAUK,oBAAoB,aAClC,UAAU,qBAAqB,MAC7B,QAAQ,OAAO,eAAe,kBAAkB,gBAAgB"}
|
package/dist/drain-pipeline.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
//#region src/drain-pipeline.d.ts
|
|
2
2
|
interface DrainPipelineOptions<T = unknown> {
|
|
3
3
|
batch?: {
|
|
4
|
-
/** Maximum events per batch. @default 50 */
|
|
4
|
+
/** Maximum events per batch. @default 50 */
|
|
5
|
+
size?: number;
|
|
6
|
+
/** Max time an event can stay buffered before flush. @default 5000 */
|
|
5
7
|
intervalMs?: number;
|
|
6
8
|
};
|
|
7
9
|
retry?: {
|
|
8
|
-
/** Total attempts including first try. @default 3 */
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
/** Total attempts including first try. @default 3 */
|
|
11
|
+
maxAttempts?: number;
|
|
12
|
+
/** Delay strategy between attempts. @default 'exponential' */
|
|
13
|
+
backoff?: 'exponential' | 'linear' | 'fixed';
|
|
14
|
+
/** Base delay for first retry. @default 1000 */
|
|
15
|
+
initialDelayMs?: number;
|
|
16
|
+
/** Max delay cap. @default 30000 */
|
|
17
|
+
maxDelayMs?: number;
|
|
18
|
+
/** Add random jitter to delays. @default true */
|
|
12
19
|
jitter?: boolean;
|
|
13
20
|
};
|
|
14
21
|
/** Max buffered events before dropping. @default 1000 */
|