@zuplo/cli 7.11.0 → 7.11.3
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/node_modules/@hono/node-server/README.md +2 -0
- package/node_modules/@hono/node-server/dist/index.cjs +1 -1
- package/node_modules/@hono/node-server/dist/index.mjs +1 -1
- package/node_modules/@hono/node-server/dist/serve-static.cjs +2 -1
- package/node_modules/@hono/node-server/dist/serve-static.mjs +2 -1
- package/node_modules/@hono/node-server/package.json +1 -1
- package/node_modules/@posthog/core/dist/metrics/index.d.ts +9 -0
- package/node_modules/@posthog/core/dist/metrics/index.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/metrics/index.js +38 -3
- package/node_modules/@posthog/core/dist/metrics/index.mjs +38 -3
- package/node_modules/@posthog/core/dist/metrics/types.d.ts +7 -2
- package/node_modules/@posthog/core/dist/metrics/types.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/traces/ids.d.ts.map +1 -1
- package/node_modules/@posthog/core/dist/traces/ids.js +2 -2
- package/node_modules/@posthog/core/dist/traces/ids.mjs +2 -2
- package/node_modules/@posthog/core/package.json +2 -2
- package/node_modules/@posthog/core/src/metrics/index.spec.ts +75 -0
- package/node_modules/@posthog/core/src/metrics/index.ts +60 -0
- package/node_modules/@posthog/core/src/metrics/types.ts +7 -1
- package/node_modules/@posthog/core/src/traces/ids.ts +4 -2
- package/node_modules/@posthog/types/dist/capture-metric.d.ts +10 -0
- package/node_modules/@posthog/types/dist/capture-metric.d.ts.map +1 -1
- package/node_modules/@posthog/types/dist/index.d.ts +1 -1
- package/node_modules/@posthog/types/dist/index.d.ts.map +1 -1
- package/node_modules/@posthog/types/package.json +1 -1
- package/node_modules/@posthog/types/src/capture-metric.ts +11 -0
- package/node_modules/@posthog/types/src/index.ts +1 -0
- package/node_modules/@zuplo/core/customer.cli.minified.js +80 -80
- package/node_modules/@zuplo/core/index.minified.js +85 -85
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +5 -2
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/out/esm/{chunk-YJ2BHVUH.js → chunk-CDEAY3VY.js} +2 -2
- package/node_modules/@zuplo/runtime/out/esm/chunk-LVSZ3WTO.js +37 -0
- package/node_modules/@zuplo/runtime/out/esm/chunk-LVSZ3WTO.js.map +1 -0
- package/node_modules/@zuplo/runtime/out/esm/{chunk-VTO3F6DK.js → chunk-NUVXDVLJ.js} +2 -2
- package/node_modules/@zuplo/runtime/out/esm/{chunk-6YPRGG62.js → chunk-TPYCFLC7.js} +109 -109
- package/node_modules/@zuplo/runtime/out/esm/chunk-TPYCFLC7.js.map +1 -0
- package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/internal/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mocks/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/sdks/aws/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/types/index.d.ts +43 -43
- package/node_modules/@zuplo/runtime/out/types/internal/index.d.ts +14 -0
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/package.json +15 -12
- package/dist/__tests__/archive-utils.test.d.ts +0 -2
- package/dist/__tests__/archive-utils.test.d.ts.map +0 -1
- package/dist/__tests__/archive-utils.test.js +0 -50
- package/dist/__tests__/archive-utils.test.js.map +0 -1
- package/dist/__tests__/import-openapi.test.d.ts +0 -2
- package/dist/__tests__/import-openapi.test.d.ts.map +0 -1
- package/dist/__tests__/import-openapi.test.js +0 -251
- package/dist/__tests__/import-openapi.test.js.map +0 -1
- package/dist/__tests__/integration/confirm-linked-config.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/confirm-linked-config.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/confirm-linked-config.integration.test.js +0 -202
- package/dist/__tests__/integration/confirm-linked-config.integration.test.js.map +0 -1
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.js +0 -184
- package/dist/__tests__/integration/confirm-production-deploy.integration.test.js.map +0 -1
- package/dist/__tests__/integration/custom-domain.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/custom-domain.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/custom-domain.integration.test.js +0 -563
- package/dist/__tests__/integration/custom-domain.integration.test.js.map +0 -1
- package/dist/__tests__/integration/delete.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/delete.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/delete.integration.test.js +0 -262
- package/dist/__tests__/integration/delete.integration.test.js.map +0 -1
- package/dist/__tests__/integration/deploy.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/deploy.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/deploy.integration.test.js +0 -519
- package/dist/__tests__/integration/deploy.integration.test.js.map +0 -1
- package/dist/__tests__/integration/get-project-param.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/get-project-param.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/get-project-param.integration.test.js +0 -305
- package/dist/__tests__/integration/get-project-param.integration.test.js.map +0 -1
- package/dist/__tests__/integration/info.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/info.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/info.integration.test.js +0 -293
- package/dist/__tests__/integration/info.integration.test.js.map +0 -1
- package/dist/__tests__/integration/jest-mocks-setup.d.ts +0 -2
- package/dist/__tests__/integration/jest-mocks-setup.d.ts.map +0 -1
- package/dist/__tests__/integration/jest-mocks-setup.js +0 -104
- package/dist/__tests__/integration/jest-mocks-setup.js.map +0 -1
- package/dist/__tests__/integration/jest-setup.d.ts +0 -2
- package/dist/__tests__/integration/jest-setup.d.ts.map +0 -1
- package/dist/__tests__/integration/jest-setup.js +0 -12
- package/dist/__tests__/integration/jest-setup.js.map +0 -1
- package/dist/__tests__/integration/link.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/link.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/link.integration.test.js +0 -395
- package/dist/__tests__/integration/link.integration.test.js.map +0 -1
- package/dist/__tests__/integration/linked-config-cascade.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/linked-config-cascade.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/linked-config-cascade.integration.test.js +0 -179
- package/dist/__tests__/integration/linked-config-cascade.integration.test.js.map +0 -1
- package/dist/__tests__/integration/list.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/list.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/list.integration.test.js +0 -300
- package/dist/__tests__/integration/list.integration.test.js.map +0 -1
- package/dist/__tests__/integration/source-upgrade.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/source-upgrade.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/source-upgrade.integration.test.js +0 -100
- package/dist/__tests__/integration/source-upgrade.integration.test.js.map +0 -1
- package/dist/__tests__/integration/test-utils.d.ts +0 -30
- package/dist/__tests__/integration/test-utils.d.ts.map +0 -1
- package/dist/__tests__/integration/test-utils.js +0 -82
- package/dist/__tests__/integration/test-utils.js.map +0 -1
- package/dist/__tests__/integration/tunnel.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/tunnel.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/tunnel.integration.test.js +0 -486
- package/dist/__tests__/integration/tunnel.integration.test.js.map +0 -1
- package/dist/__tests__/integration/variable.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/variable.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/variable.integration.test.js +0 -258
- package/dist/__tests__/integration/variable.integration.test.js.map +0 -1
- package/dist/__tests__/integration/whoami.integration.test.d.ts +0 -2
- package/dist/__tests__/integration/whoami.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/whoami.integration.test.js +0 -116
- package/dist/__tests__/integration/whoami.integration.test.js.map +0 -1
- package/dist/__tests__/outdated.test.d.ts +0 -2
- package/dist/__tests__/outdated.test.d.ts.map +0 -1
- package/dist/__tests__/outdated.test.js +0 -67
- package/dist/__tests__/outdated.test.js.map +0 -1
- package/dist/__tests__/populate.test.d.ts +0 -2
- package/dist/__tests__/populate.test.d.ts.map +0 -1
- package/dist/__tests__/populate.test.js +0 -445
- package/dist/__tests__/populate.test.js.map +0 -1
- package/dist/__tests__/tsconfig-upgrader.test.d.ts +0 -2
- package/dist/__tests__/tsconfig-upgrader.test.d.ts.map +0 -1
- package/dist/__tests__/tsconfig-upgrader.test.js +0 -31
- package/dist/__tests__/tsconfig-upgrader.test.js.map +0 -1
- package/dist/ca-certificate/validation.test.d.ts +0 -2
- package/dist/ca-certificate/validation.test.d.ts.map +0 -1
- package/dist/ca-certificate/validation.test.js +0 -131
- package/dist/ca-certificate/validation.test.js.map +0 -1
- package/dist/common/analytics/cli-invocation.test.d.ts +0 -2
- package/dist/common/analytics/cli-invocation.test.d.ts.map +0 -1
- package/dist/common/analytics/cli-invocation.test.js +0 -51
- package/dist/common/analytics/cli-invocation.test.js.map +0 -1
- package/dist/common/analytics/package-manager.test.d.ts +0 -2
- package/dist/common/analytics/package-manager.test.d.ts.map +0 -1
- package/dist/common/analytics/package-manager.test.js +0 -163
- package/dist/common/analytics/package-manager.test.js.map +0 -1
- package/dist/common/cli-dispatcher.test.d.ts +0 -2
- package/dist/common/cli-dispatcher.test.d.ts.map +0 -1
- package/dist/common/cli-dispatcher.test.js +0 -80
- package/dist/common/cli-dispatcher.test.js.map +0 -1
- package/dist/common/middleware/check-pnpm-lifecycle.test.d.ts +0 -2
- package/dist/common/middleware/check-pnpm-lifecycle.test.d.ts.map +0 -1
- package/dist/common/middleware/check-pnpm-lifecycle.test.js +0 -125
- package/dist/common/middleware/check-pnpm-lifecycle.test.js.map +0 -1
- package/dist/common/middleware/get-environment-param.test.d.ts +0 -2
- package/dist/common/middleware/get-environment-param.test.d.ts.map +0 -1
- package/dist/common/middleware/get-environment-param.test.js +0 -57
- package/dist/common/middleware/get-environment-param.test.js.map +0 -1
- package/dist/common/read-linked-config.test.d.ts +0 -2
- package/dist/common/read-linked-config.test.d.ts.map +0 -1
- package/dist/common/read-linked-config.test.js +0 -363
- package/dist/common/read-linked-config.test.js.map +0 -1
- package/dist/common/terminal.test.d.ts +0 -2
- package/dist/common/terminal.test.d.ts.map +0 -1
- package/dist/common/terminal.test.js +0 -101
- package/dist/common/terminal.test.js.map +0 -1
- package/dist/common/utils/build-environment-prompt-choices.test.d.ts +0 -2
- package/dist/common/utils/build-environment-prompt-choices.test.d.ts.map +0 -1
- package/dist/common/utils/build-environment-prompt-choices.test.js +0 -97
- package/dist/common/utils/build-environment-prompt-choices.test.js.map +0 -1
- package/dist/common/utils/format-environment-type.test.d.ts +0 -2
- package/dist/common/utils/format-environment-type.test.d.ts.map +0 -1
- package/dist/common/utils/format-environment-type.test.js +0 -32
- package/dist/common/utils/format-environment-type.test.js.map +0 -1
- package/dist/common/utils/pnpm-lifecycle.test.d.ts +0 -2
- package/dist/common/utils/pnpm-lifecycle.test.d.ts.map +0 -1
- package/dist/common/utils/pnpm-lifecycle.test.js +0 -196
- package/dist/common/utils/pnpm-lifecycle.test.js.map +0 -1
- package/dist/common/utils/pretty-print-environment-prompt.test.d.ts +0 -2
- package/dist/common/utils/pretty-print-environment-prompt.test.d.ts.map +0 -1
- package/dist/common/utils/pretty-print-environment-prompt.test.js +0 -42
- package/dist/common/utils/pretty-print-environment-prompt.test.js.map +0 -1
- package/dist/common/utils/sort-environments-for-prompt.test.d.ts +0 -2
- package/dist/common/utils/sort-environments-for-prompt.test.d.ts.map +0 -1
- package/dist/common/utils/sort-environments-for-prompt.test.js +0 -82
- package/dist/common/utils/sort-environments-for-prompt.test.js.map +0 -1
- package/dist/common/utils/stringify-config.test.d.ts +0 -2
- package/dist/common/utils/stringify-config.test.d.ts.map +0 -1
- package/dist/common/utils/stringify-config.test.js +0 -80
- package/dist/common/utils/stringify-config.test.js.map +0 -1
- package/dist/common/validators/argument-validators.spec.d.ts +0 -2
- package/dist/common/validators/argument-validators.spec.d.ts.map +0 -1
- package/dist/common/validators/argument-validators.spec.js +0 -181
- package/dist/common/validators/argument-validators.spec.js.map +0 -1
- package/dist/common/worker-output.test.d.ts +0 -2
- package/dist/common/worker-output.test.d.ts.map +0 -1
- package/dist/common/worker-output.test.js +0 -32
- package/dist/common/worker-output.test.js.map +0 -1
- package/dist/deploy/archive.local-registry.test.d.ts +0 -2
- package/dist/deploy/archive.local-registry.test.d.ts.map +0 -1
- package/dist/deploy/archive.local-registry.test.js +0 -100
- package/dist/deploy/archive.local-registry.test.js.map +0 -1
- package/dist/deploy/archive.test.d.ts +0 -2
- package/dist/deploy/archive.test.d.ts.map +0 -1
- package/dist/deploy/archive.test.js +0 -248
- package/dist/deploy/archive.test.js.map +0 -1
- package/dist/deploy/classify-build-probe.test.d.ts +0 -2
- package/dist/deploy/classify-build-probe.test.d.ts.map +0 -1
- package/dist/deploy/classify-build-probe.test.js +0 -51
- package/dist/deploy/classify-build-probe.test.js.map +0 -1
- package/dist/deploy/poll-deployment.test.d.ts +0 -2
- package/dist/deploy/poll-deployment.test.d.ts.map +0 -1
- package/dist/deploy/poll-deployment.test.js +0 -158
- package/dist/deploy/poll-deployment.test.js.map +0 -1
- package/dist/dev/zuplo-local-gitignore.test.d.ts +0 -2
- package/dist/dev/zuplo-local-gitignore.test.d.ts.map +0 -1
- package/dist/dev/zuplo-local-gitignore.test.js +0 -58
- package/dist/dev/zuplo-local-gitignore.test.js.map +0 -1
- package/dist/editor/e2e/editor.spec.d.ts +0 -2
- package/dist/editor/e2e/editor.spec.d.ts.map +0 -1
- package/dist/editor/e2e/editor.spec.js +0 -44
- package/dist/editor/e2e/editor.spec.js.map +0 -1
- package/dist/link/project-type.test.d.ts +0 -2
- package/dist/link/project-type.test.d.ts.map +0 -1
- package/dist/link/project-type.test.js +0 -225
- package/dist/link/project-type.test.js.map +0 -1
- package/dist/lint/resolve-binary.test.d.ts +0 -2
- package/dist/lint/resolve-binary.test.d.ts.map +0 -1
- package/dist/lint/resolve-binary.test.js +0 -155
- package/dist/lint/resolve-binary.test.js.map +0 -1
- package/dist/open-api/convert/handler.spec.d.ts +0 -2
- package/dist/open-api/convert/handler.spec.d.ts.map +0 -1
- package/dist/open-api/convert/handler.spec.js +0 -301
- package/dist/open-api/convert/handler.spec.js.map +0 -1
- package/dist/open-api/merge/handler.spec.d.ts +0 -2
- package/dist/open-api/merge/handler.spec.d.ts.map +0 -1
- package/dist/open-api/merge/handler.spec.js +0 -673
- package/dist/open-api/merge/handler.spec.js.map +0 -1
- package/dist/open-api/overlay/handler.spec.d.ts +0 -2
- package/dist/open-api/overlay/handler.spec.d.ts.map +0 -1
- package/dist/open-api/overlay/handler.spec.js +0 -346
- package/dist/open-api/overlay/handler.spec.js.map +0 -1
- package/dist/source/ai-gateway/files.test.d.ts +0 -2
- package/dist/source/ai-gateway/files.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/files.test.js +0 -135
- package/dist/source/ai-gateway/files.test.js.map +0 -1
- package/dist/source/ai-gateway/handler.test.d.ts +0 -2
- package/dist/source/ai-gateway/handler.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/handler.test.js +0 -113
- package/dist/source/ai-gateway/handler.test.js.map +0 -1
- package/dist/source/ai-gateway/package.test.d.ts +0 -2
- package/dist/source/ai-gateway/package.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/package.test.js +0 -30
- package/dist/source/ai-gateway/package.test.js.map +0 -1
- package/dist/source/ai-gateway/planner.test.d.ts +0 -2
- package/dist/source/ai-gateway/planner.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/planner.test.js +0 -330
- package/dist/source/ai-gateway/planner.test.js.map +0 -1
- package/dist/source/ai-gateway/release.test.d.ts +0 -2
- package/dist/source/ai-gateway/release.test.d.ts.map +0 -1
- package/dist/source/ai-gateway/release.test.js +0 -62
- package/dist/source/ai-gateway/release.test.js.map +0 -1
- package/dist/test/invoke-test.test.d.ts +0 -2
- package/dist/test/invoke-test.test.d.ts.map +0 -1
- package/dist/test/invoke-test.test.js +0 -150
- package/dist/test/invoke-test.test.js.map +0 -1
- package/dist/test/test-files.test.d.ts +0 -2
- package/dist/test/test-files.test.d.ts.map +0 -1
- package/dist/test/test-files.test.js +0 -57
- package/dist/test/test-files.test.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/file-format.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/file-format.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/file-format.spec.js +0 -289
- package/node_modules/@zuplo/openapi-tools/dist/file-format.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/merge-fixtures.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/merge-fixtures.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/merge-fixtures.spec.js +0 -181
- package/node_modules/@zuplo/openapi-tools/dist/merge-fixtures.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/merge.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/merge.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/merge.spec.js +0 -399
- package/node_modules/@zuplo/openapi-tools/dist/merge.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/overlay.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/overlay.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/overlay.spec.js +0 -779
- package/node_modules/@zuplo/openapi-tools/dist/overlay.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/path-transform.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/path-transform.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/path-transform.spec.js +0 -269
- package/node_modules/@zuplo/openapi-tools/dist/path-transform.spec.js.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/url-utils.spec.d.ts +0 -2
- package/node_modules/@zuplo/openapi-tools/dist/url-utils.spec.d.ts.map +0 -1
- package/node_modules/@zuplo/openapi-tools/dist/url-utils.spec.js +0 -93
- package/node_modules/@zuplo/openapi-tools/dist/url-utils.spec.js.map +0 -1
- package/node_modules/@zuplo/runtime/out/esm/chunk-6YPRGG62.js.map +0 -1
- package/node_modules/@zuplo/runtime/out/esm/chunk-PBDT4FDO.js +0 -37
- package/node_modules/@zuplo/runtime/out/esm/chunk-PBDT4FDO.js.map +0 -1
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-YJ2BHVUH.js.map → chunk-CDEAY3VY.js.map} +0 -0
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-PBDT4FDO.js.LEGAL.txt → chunk-LVSZ3WTO.js.LEGAL.txt} +0 -0
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-VTO3F6DK.js.map → chunk-NUVXDVLJ.js.map} +0 -0
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-6YPRGG62.js.LEGAL.txt → chunk-TPYCFLC7.js.LEGAL.txt} +0 -0
|
@@ -224,6 +224,8 @@ app.use('/static/*', serveStatic({ root: './static' }))
|
|
|
224
224
|
|
|
225
225
|
Notice that `root` here is not relative to `src/index.ts`, rather to `my-hono-project`.
|
|
226
226
|
|
|
227
|
+
Only `GET` and `HEAD` requests are served. Requests with other methods are passed to the next middleware.
|
|
228
|
+
|
|
227
229
|
### Options
|
|
228
230
|
|
|
229
231
|
#### `allowPercentInPath`
|
|
@@ -846,7 +846,7 @@ const makeCloseHandler = (req, incoming, outgoing, needsBodyCleanup) => () => {
|
|
|
846
846
|
if (incoming.errored) {
|
|
847
847
|
recordBodyBufferedBeforeDisconnect(incoming);
|
|
848
848
|
req[abortRequest](incoming.errored.toString());
|
|
849
|
-
} else if (!outgoing.writableFinished) {
|
|
849
|
+
} else if (!outgoing.writableFinished || incoming instanceof node_http2.Http2ServerRequest && incoming.aborted) {
|
|
850
850
|
recordBodyBufferedBeforeDisconnect(incoming);
|
|
851
851
|
req[abortRequest]("Client connection prematurely closed.");
|
|
852
852
|
}
|
|
@@ -845,7 +845,7 @@ const makeCloseHandler = (req, incoming, outgoing, needsBodyCleanup) => () => {
|
|
|
845
845
|
if (incoming.errored) {
|
|
846
846
|
recordBodyBufferedBeforeDisconnect(incoming);
|
|
847
847
|
req[abortRequest](incoming.errored.toString());
|
|
848
|
-
} else if (!outgoing.writableFinished) {
|
|
848
|
+
} else if (!outgoing.writableFinished || incoming instanceof Http2ServerRequest && incoming.aborted) {
|
|
849
849
|
recordBodyBufferedBeforeDisconnect(incoming);
|
|
850
850
|
req[abortRequest]("Client connection prematurely closed.");
|
|
851
851
|
}
|
|
@@ -74,6 +74,7 @@ const serveStatic = (options = { root: "" }) => {
|
|
|
74
74
|
if (root !== "" && !(0, node_fs.existsSync)(root)) console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
|
|
75
75
|
return async (c, next) => {
|
|
76
76
|
if (c.finalized) return next();
|
|
77
|
+
if (c.req.method !== "GET" && c.req.method !== "HEAD") return next();
|
|
77
78
|
let filename;
|
|
78
79
|
if (optionPath) filename = optionPath;
|
|
79
80
|
else try {
|
|
@@ -115,7 +116,7 @@ const serveStatic = (options = { root: "" }) => {
|
|
|
115
116
|
const size = stats.size;
|
|
116
117
|
const range = c.req.header("range") || "";
|
|
117
118
|
c.header("Last-Modified", stats.mtime.toUTCString());
|
|
118
|
-
if (c.req.method
|
|
119
|
+
if (c.req.method === "HEAD") {
|
|
119
120
|
c.header("Content-Length", size.toString());
|
|
120
121
|
c.status(200);
|
|
121
122
|
result = c.body(null);
|
|
@@ -73,6 +73,7 @@ const serveStatic = (options = { root: "" }) => {
|
|
|
73
73
|
if (root !== "" && !existsSync(root)) console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
|
|
74
74
|
return async (c, next) => {
|
|
75
75
|
if (c.finalized) return next();
|
|
76
|
+
if (c.req.method !== "GET" && c.req.method !== "HEAD") return next();
|
|
76
77
|
let filename;
|
|
77
78
|
if (optionPath) filename = optionPath;
|
|
78
79
|
else try {
|
|
@@ -114,7 +115,7 @@ const serveStatic = (options = { root: "" }) => {
|
|
|
114
115
|
const size = stats.size;
|
|
115
116
|
const range = c.req.header("range") || "";
|
|
116
117
|
c.header("Last-Modified", stats.mtime.toUTCString());
|
|
117
|
-
if (c.req.method
|
|
118
|
+
if (c.req.method === "HEAD") {
|
|
118
119
|
c.header("Content-Length", size.toString());
|
|
119
120
|
c.status(200);
|
|
120
121
|
result = c.body(null);
|
|
@@ -14,6 +14,10 @@ import type { MetricsHost, ResolvedPostHogMetricsConfig } from './types';
|
|
|
14
14
|
* Deliberately unlike logs, no per-user context (distinct ID, session ID) is
|
|
15
15
|
* attached: every attribute value creates a new series, and per-user series
|
|
16
16
|
* are the canonical metrics-cardinality explosion.
|
|
17
|
+
*
|
|
18
|
+
* A sample recorded inside a sampled span stamps its series with an exemplar
|
|
19
|
+
* (trace ID, span ID, value). One per series per window, last sample wins, so a
|
|
20
|
+
* metric point links to one representative trace at no cardinality cost.
|
|
17
21
|
*/
|
|
18
22
|
export declare class PostHogMetrics {
|
|
19
23
|
private readonly _instance;
|
|
@@ -46,6 +50,11 @@ export declare class PostHogMetrics {
|
|
|
46
50
|
/** Clears the flush timer, drops the current window, and invalidates in-flight flushes. */
|
|
47
51
|
reset(): void;
|
|
48
52
|
private _capture;
|
|
53
|
+
/**
|
|
54
|
+
* The sampled span a sample is recorded in. An unsampled span is never
|
|
55
|
+
* exported, so an exemplar pointing at it would link to a missing trace.
|
|
56
|
+
*/
|
|
57
|
+
private _activeTraceContext;
|
|
49
58
|
/**
|
|
50
59
|
* Cardinality gate for adding a series to the live window — warns once per
|
|
51
60
|
* window when the cap is hit. Applied on capture and on merge-back alike.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EAOpB,kBAAkB,EAEnB,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAetC,OAAO,KAAK,EAAE,WAAW,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAA;AAoCxE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAc;IA0BvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IA3B1B,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAI3B;IAGD,OAAO,CAAC,aAAa,CAA6B;IAElD,OAAO,CAAC,gBAAgB,CAAQ;IAIhC,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,oBAAoB,CAAoB;IAChD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,yBAAyB,CAAI;IACrC,OAAO,CAAC,YAAY,CAAY;IAIhC,OAAO,CAAC,WAAW,CAAI;IAEvB,YACmB,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,4BAA4B,EACrC,OAAO,EAAE,MAAM,EAC9B;IAEJ,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAE3E;IAED,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAEvE;IAED,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAE3E;IAED,iFAAiF;IACjF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAerB;IAED;;;;;;OAMG;IACH,WAAW,IAAI,kBAAkB,GAAG,IAAI,CAUvC;IAED,2FAA2F;IAC3F,KAAK,IAAI,IAAI,CAWZ;IAED,OAAO,CAAC,QAAQ;IA0EhB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAY3B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,KAAK;IA6Bb,OAAO,CAAC,cAAc;IAyBtB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,eAAe;YAYT,QAAQ;IAyDtB,OAAO,CAAC,aAAa;IASrB;;;OAGG;IACH,OAAO,CAAC,aAAa;IA4DrB,oFAAoF;IACpF,OAAO,CAAC,gBAAgB;CAuCzB;AAqBD,OAAO,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AACnH,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAC/C,YAAY,EAAE,WAAW,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -39,6 +39,7 @@ const flush_timer_js_namespaceObject = require("../utils/flush-timer.js");
|
|
|
39
39
|
const retry_after_js_namespaceObject = require("../utils/retry-after.js");
|
|
40
40
|
const backoff_js_namespaceObject = require("../utils/backoff.js");
|
|
41
41
|
const otlp_any_value_js_namespaceObject = require("../utils/otlp-any-value.js");
|
|
42
|
+
const traceparent_js_namespaceObject = require("../traces/traceparent.js");
|
|
42
43
|
const external_metrics_utils_js_namespaceObject = require("./metrics-utils.js");
|
|
43
44
|
const external_config_js_namespaceObject = require("./config.js");
|
|
44
45
|
const OTLP_TEMPORALITY_DELTA = 1;
|
|
@@ -157,8 +158,23 @@ class PostHogMetrics {
|
|
|
157
158
|
this._logger.warn(`Metric name '${filtered.name}' is already used as a ${seenType}; recording it as a ${filtered.type} too will blend both series in charts. Use a distinct name.`);
|
|
158
159
|
}
|
|
159
160
|
this._fold(state, filtered.value);
|
|
161
|
+
const traceContext = this._activeTraceContext();
|
|
162
|
+
if (traceContext) state.exemplar = {
|
|
163
|
+
...traceContext,
|
|
164
|
+
value: filtered.value,
|
|
165
|
+
timeMs: Date.now()
|
|
166
|
+
};
|
|
160
167
|
this._armFlushTimer();
|
|
161
168
|
}
|
|
169
|
+
_activeTraceContext() {
|
|
170
|
+
try {
|
|
171
|
+
const parsed = (0, traceparent_js_namespaceObject.parseTraceparent)(this._instance.getActiveSpan?.()?.traceparent());
|
|
172
|
+
if (parsed && parsed.flags === traceparent_js_namespaceObject.TRACE_FLAGS_SAMPLED) return {
|
|
173
|
+
traceId: parsed.traceId,
|
|
174
|
+
spanId: parsed.spanId
|
|
175
|
+
};
|
|
176
|
+
} catch {}
|
|
177
|
+
}
|
|
162
178
|
_admitNewSeries() {
|
|
163
179
|
if (this._series.size < this._config.maxSeriesPerFlush) return true;
|
|
164
180
|
if (!this._seriesCapWarned) {
|
|
@@ -288,19 +304,22 @@ class PostHogMetrics {
|
|
|
288
304
|
}
|
|
289
305
|
const attributes = (0, otlp_any_value_js_namespaceObject.toOtlpKeyValueList)(state.attributes ?? {}, this._logger);
|
|
290
306
|
const startNano = (0, external_metrics_utils_js_namespaceObject.msToUnixNano)(state.windowStartMs);
|
|
307
|
+
const exemplars = toOtlpExemplars(state.exemplar);
|
|
291
308
|
if ('count' === state.type) {
|
|
292
309
|
const dp = {
|
|
293
310
|
attributes,
|
|
294
311
|
startTimeUnixNano: startNano,
|
|
295
312
|
timeUnixNano: nowNano,
|
|
296
|
-
asDouble: state.total ?? 0
|
|
313
|
+
asDouble: state.total ?? 0,
|
|
314
|
+
...exemplars
|
|
297
315
|
};
|
|
298
316
|
metric.sum.dataPoints.push(dp);
|
|
299
317
|
} else if ('gauge' === state.type) {
|
|
300
318
|
const dp = {
|
|
301
319
|
attributes,
|
|
302
320
|
timeUnixNano: nowNano,
|
|
303
|
-
asDouble: state.last ?? 0
|
|
321
|
+
asDouble: state.last ?? 0,
|
|
322
|
+
...exemplars
|
|
304
323
|
};
|
|
305
324
|
metric.gauge.dataPoints.push(dp);
|
|
306
325
|
} else if (state.hist) {
|
|
@@ -313,7 +332,8 @@ class PostHogMetrics {
|
|
|
313
332
|
min: state.hist.min,
|
|
314
333
|
max: state.hist.max,
|
|
315
334
|
bucketCounts: state.hist.bucketCounts,
|
|
316
|
-
explicitBounds: external_metrics_utils_js_namespaceObject.DEFAULT_HISTOGRAM_BOUNDS
|
|
335
|
+
explicitBounds: external_metrics_utils_js_namespaceObject.DEFAULT_HISTOGRAM_BOUNDS,
|
|
336
|
+
...exemplars
|
|
317
337
|
};
|
|
318
338
|
metric.histogram.dataPoints.push(dp);
|
|
319
339
|
}
|
|
@@ -328,6 +348,7 @@ class PostHogMetrics {
|
|
|
328
348
|
continue;
|
|
329
349
|
}
|
|
330
350
|
current.windowStartMs = Math.min(current.windowStartMs, old.windowStartMs);
|
|
351
|
+
current.exemplar = current.exemplar ?? old.exemplar;
|
|
331
352
|
switch(current.type){
|
|
332
353
|
case 'count':
|
|
333
354
|
current.total = (current.total ?? 0) + (old.total ?? 0);
|
|
@@ -347,6 +368,20 @@ class PostHogMetrics {
|
|
|
347
368
|
}
|
|
348
369
|
}
|
|
349
370
|
}
|
|
371
|
+
function toOtlpExemplars(exemplar) {
|
|
372
|
+
if (!exemplar) return {};
|
|
373
|
+
return {
|
|
374
|
+
exemplars: [
|
|
375
|
+
{
|
|
376
|
+
filteredAttributes: [],
|
|
377
|
+
timeUnixNano: (0, external_metrics_utils_js_namespaceObject.msToUnixNano)(exemplar.timeMs),
|
|
378
|
+
asDouble: exemplar.value,
|
|
379
|
+
traceId: exemplar.traceId,
|
|
380
|
+
spanId: exemplar.spanId
|
|
381
|
+
}
|
|
382
|
+
]
|
|
383
|
+
};
|
|
384
|
+
}
|
|
350
385
|
exports.DEFAULT_HISTOGRAM_BOUNDS = __webpack_exports__.DEFAULT_HISTOGRAM_BOUNDS;
|
|
351
386
|
exports.PostHogMetrics = __webpack_exports__.PostHogMetrics;
|
|
352
387
|
exports.buildMetricsResourceAttributes = __webpack_exports__.buildMetricsResourceAttributes;
|
|
@@ -3,6 +3,7 @@ import { FlushTimer } from "../utils/flush-timer.mjs";
|
|
|
3
3
|
import { RetryAfterWindow } from "../utils/retry-after.mjs";
|
|
4
4
|
import { MAX_FLUSH_BACKOFF_MS, NO_JITTER, backoffDelayMs, drawJitter } from "../utils/backoff.mjs";
|
|
5
5
|
import { toOtlpKeyValueList } from "../utils/otlp-any-value.mjs";
|
|
6
|
+
import { TRACE_FLAGS_SAMPLED, parseTraceparent } from "../traces/traceparent.mjs";
|
|
6
7
|
import { DEFAULT_HISTOGRAM_BOUNDS, bucketIndexFor, buildMetricsResourceAttributes, buildOtlpMetricsPayload, msToUnixNano, seriesKey } from "./metrics-utils.mjs";
|
|
7
8
|
const OTLP_TEMPORALITY_DELTA = 1;
|
|
8
9
|
class PostHogMetrics {
|
|
@@ -120,8 +121,23 @@ class PostHogMetrics {
|
|
|
120
121
|
this._logger.warn(`Metric name '${filtered.name}' is already used as a ${seenType}; recording it as a ${filtered.type} too will blend both series in charts. Use a distinct name.`);
|
|
121
122
|
}
|
|
122
123
|
this._fold(state, filtered.value);
|
|
124
|
+
const traceContext = this._activeTraceContext();
|
|
125
|
+
if (traceContext) state.exemplar = {
|
|
126
|
+
...traceContext,
|
|
127
|
+
value: filtered.value,
|
|
128
|
+
timeMs: Date.now()
|
|
129
|
+
};
|
|
123
130
|
this._armFlushTimer();
|
|
124
131
|
}
|
|
132
|
+
_activeTraceContext() {
|
|
133
|
+
try {
|
|
134
|
+
const parsed = parseTraceparent(this._instance.getActiveSpan?.()?.traceparent());
|
|
135
|
+
if (parsed && parsed.flags === TRACE_FLAGS_SAMPLED) return {
|
|
136
|
+
traceId: parsed.traceId,
|
|
137
|
+
spanId: parsed.spanId
|
|
138
|
+
};
|
|
139
|
+
} catch {}
|
|
140
|
+
}
|
|
125
141
|
_admitNewSeries() {
|
|
126
142
|
if (this._series.size < this._config.maxSeriesPerFlush) return true;
|
|
127
143
|
if (!this._seriesCapWarned) {
|
|
@@ -251,19 +267,22 @@ class PostHogMetrics {
|
|
|
251
267
|
}
|
|
252
268
|
const attributes = toOtlpKeyValueList(state.attributes ?? {}, this._logger);
|
|
253
269
|
const startNano = msToUnixNano(state.windowStartMs);
|
|
270
|
+
const exemplars = toOtlpExemplars(state.exemplar);
|
|
254
271
|
if ('count' === state.type) {
|
|
255
272
|
const dp = {
|
|
256
273
|
attributes,
|
|
257
274
|
startTimeUnixNano: startNano,
|
|
258
275
|
timeUnixNano: nowNano,
|
|
259
|
-
asDouble: state.total ?? 0
|
|
276
|
+
asDouble: state.total ?? 0,
|
|
277
|
+
...exemplars
|
|
260
278
|
};
|
|
261
279
|
metric.sum.dataPoints.push(dp);
|
|
262
280
|
} else if ('gauge' === state.type) {
|
|
263
281
|
const dp = {
|
|
264
282
|
attributes,
|
|
265
283
|
timeUnixNano: nowNano,
|
|
266
|
-
asDouble: state.last ?? 0
|
|
284
|
+
asDouble: state.last ?? 0,
|
|
285
|
+
...exemplars
|
|
267
286
|
};
|
|
268
287
|
metric.gauge.dataPoints.push(dp);
|
|
269
288
|
} else if (state.hist) {
|
|
@@ -276,7 +295,8 @@ class PostHogMetrics {
|
|
|
276
295
|
min: state.hist.min,
|
|
277
296
|
max: state.hist.max,
|
|
278
297
|
bucketCounts: state.hist.bucketCounts,
|
|
279
|
-
explicitBounds: DEFAULT_HISTOGRAM_BOUNDS
|
|
298
|
+
explicitBounds: DEFAULT_HISTOGRAM_BOUNDS,
|
|
299
|
+
...exemplars
|
|
280
300
|
};
|
|
281
301
|
metric.histogram.dataPoints.push(dp);
|
|
282
302
|
}
|
|
@@ -291,6 +311,7 @@ class PostHogMetrics {
|
|
|
291
311
|
continue;
|
|
292
312
|
}
|
|
293
313
|
current.windowStartMs = Math.min(current.windowStartMs, old.windowStartMs);
|
|
314
|
+
current.exemplar = current.exemplar ?? old.exemplar;
|
|
294
315
|
switch(current.type){
|
|
295
316
|
case 'count':
|
|
296
317
|
current.total = (current.total ?? 0) + (old.total ?? 0);
|
|
@@ -310,5 +331,19 @@ class PostHogMetrics {
|
|
|
310
331
|
}
|
|
311
332
|
}
|
|
312
333
|
}
|
|
334
|
+
function toOtlpExemplars(exemplar) {
|
|
335
|
+
if (!exemplar) return {};
|
|
336
|
+
return {
|
|
337
|
+
exemplars: [
|
|
338
|
+
{
|
|
339
|
+
filteredAttributes: [],
|
|
340
|
+
timeUnixNano: msToUnixNano(exemplar.timeMs),
|
|
341
|
+
asDouble: exemplar.value,
|
|
342
|
+
traceId: exemplar.traceId,
|
|
343
|
+
spanId: exemplar.spanId
|
|
344
|
+
}
|
|
345
|
+
]
|
|
346
|
+
};
|
|
347
|
+
}
|
|
313
348
|
export { resolveMetricsConfig } from "./config.mjs";
|
|
314
349
|
export { DEFAULT_HISTOGRAM_BOUNDS, PostHogMetrics, buildMetricsResourceAttributes, buildOtlpMetricsPayload };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { MetricAttributeValue, MetricAttributes, MetricType, MetricsConfig, CaptureMetricOptions, MetricSample, BeforeSendMetricFn, Metrics, OtlpNumberDataPoint, OtlpHistogramDataPoint, OtlpMetric, OtlpMetricsPayload, } from '@posthog/types';
|
|
2
|
-
import type { BeforeSendMetricFn, MetricAttributeValue, OtlpMetricsPayload } from '@posthog/types';
|
|
1
|
+
export type { MetricAttributeValue, MetricAttributes, MetricType, MetricsConfig, CaptureMetricOptions, MetricSample, BeforeSendMetricFn, Metrics, OtlpNumberDataPoint, OtlpHistogramDataPoint, OtlpMetric, OtlpMetricsPayload, OtlpExemplar, } from '@posthog/types';
|
|
2
|
+
import type { BeforeSendMetricFn, MetricAttributeValue, OtlpMetricsPayload, Span } from '@posthog/types';
|
|
3
3
|
/** Same tagged outcome shape as `SendLogsBatchOutcome` — one policy for both signals. */
|
|
4
4
|
export type SendMetricsBatchOutcome = {
|
|
5
5
|
kind: 'ok';
|
|
@@ -30,6 +30,11 @@ export interface MetricsHost {
|
|
|
30
30
|
_sendMetricsBatch(payload: OtlpMetricsPayload): Promise<SendMetricsBatchOutcome>;
|
|
31
31
|
getLibraryId(): string;
|
|
32
32
|
getLibraryVersion(): string;
|
|
33
|
+
/**
|
|
34
|
+
* The span active where a sample is recorded. A sampled one stamps the
|
|
35
|
+
* sample's series with an exemplar. Hosts without tracing leave it out.
|
|
36
|
+
*/
|
|
37
|
+
getActiveSpan?(): Span | null;
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
40
|
* Configuration for the metrics feature on `new PostHog(key, { metrics: ... })`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/metrics/types.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAClB,OAAO,EACP,mBAAmB,EACnB,sBAAsB,EACtB,UAAU,EACV,kBAAkB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/metrics/types.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAClB,OAAO,EACP,mBAAmB,EACnB,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EAClB,YAAY,GACb,MAAM,gBAAgB,CAAA;AAEvB,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAExG,yFAAyF;AACzF,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GACd;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D;IACE,IAAI,EAAE,WAAW,CAAA;IACjB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,GACD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AAErC;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;IAChF,YAAY,IAAI,MAAM,CAAA;IACtB,iBAAiB,IAAI,MAAM,CAAA;IAC3B;;;OAGG;IACH,aAAa,CAAC,IAAI,IAAI,GAAG,IAAI,CAAA;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB,0DAA0D;IAC1D,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;IAEzD;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAE1B;;;OAGG;IACH,UAAU,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,EAAE,CAAA;CACvD;AAID,MAAM,WAAW,4BAA6B,SAAQ,oBAAoB;IACxE,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;CAC1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/traces/ids.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/traces/ids.ts"],"names":[],"mappings":"AAoBA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CAe7D;AAiBD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAMD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE9D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE7D"}
|
|
@@ -31,8 +31,8 @@ const TRACE_ID_BYTES = 16;
|
|
|
31
31
|
const SPAN_ID_BYTES = 8;
|
|
32
32
|
const TRACE_ID_HEX = 2 * TRACE_ID_BYTES;
|
|
33
33
|
const SPAN_ID_HEX = 2 * SPAN_ID_BYTES;
|
|
34
|
-
const
|
|
35
|
-
const
|
|
34
|
+
const INVALID_SPAN_ID = '0000000000000000';
|
|
35
|
+
const INVALID_TRACE_ID = INVALID_SPAN_ID + INVALID_SPAN_ID;
|
|
36
36
|
const HEX_RE = /^[0-9a-f]+$/;
|
|
37
37
|
function getRandomBytes(byteLength) {
|
|
38
38
|
const bytes = new Uint8Array(byteLength);
|
|
@@ -2,8 +2,8 @@ const TRACE_ID_BYTES = 16;
|
|
|
2
2
|
const SPAN_ID_BYTES = 8;
|
|
3
3
|
const TRACE_ID_HEX = 2 * TRACE_ID_BYTES;
|
|
4
4
|
const SPAN_ID_HEX = 2 * SPAN_ID_BYTES;
|
|
5
|
-
const
|
|
6
|
-
const
|
|
5
|
+
const INVALID_SPAN_ID = '0000000000000000';
|
|
6
|
+
const INVALID_TRACE_ID = INVALID_SPAN_ID + INVALID_SPAN_ID;
|
|
7
7
|
const HEX_RE = /^[0-9a-f]+$/;
|
|
8
8
|
function getRandomBytes(byteLength) {
|
|
9
9
|
const bytes = new Uint8Array(byteLength);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.59.0",
|
|
4
4
|
"bugs": {
|
|
5
5
|
"url": "https://github.com/PostHog/posthog-js/issues"
|
|
6
6
|
},
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@posthog/types": "^1.
|
|
75
|
+
"@posthog/types": "^1.416.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@rslib/core": "0.23.2",
|
|
@@ -203,6 +203,81 @@ describe('PostHogMetrics', () => {
|
|
|
203
203
|
})
|
|
204
204
|
})
|
|
205
205
|
|
|
206
|
+
describe('exemplars', () => {
|
|
207
|
+
const TRACE_ID = '4bf92f3577b34da6a3ce929d0e0e4736'
|
|
208
|
+
const SPAN_ID = '00f067aa0ba902b7'
|
|
209
|
+
const withActiveSpan = (traceparent: string | null): any =>
|
|
210
|
+
createMockInstance({ getActiveSpan: () => ({ traceparent: () => traceparent }) })
|
|
211
|
+
|
|
212
|
+
const dataPoints = (instance: any): any[] =>
|
|
213
|
+
sentMetrics(instance).map((m) => (m.sum ?? m.gauge ?? m.histogram)!.dataPoints[0])
|
|
214
|
+
|
|
215
|
+
it('stamps every metric type with the last sample recorded inside a sampled span', async () => {
|
|
216
|
+
const instance = withActiveSpan(`00-${TRACE_ID}-${SPAN_ID}-01`)
|
|
217
|
+
const metrics = createMetrics(undefined, instance)
|
|
218
|
+
metrics.count('c', 1)
|
|
219
|
+
metrics.count('c', 4)
|
|
220
|
+
metrics.gauge('g', 7)
|
|
221
|
+
metrics.histogram('h', 12)
|
|
222
|
+
await metrics.flush()
|
|
223
|
+
|
|
224
|
+
const points = dataPoints(instance)
|
|
225
|
+
expect(points.map((p) => p.exemplars)).toEqual(
|
|
226
|
+
[4, 7, 12].map((value) => [
|
|
227
|
+
{
|
|
228
|
+
filteredAttributes: [],
|
|
229
|
+
timeUnixNano: expect.stringMatching(/^\d+$/),
|
|
230
|
+
asDouble: value,
|
|
231
|
+
traceId: TRACE_ID,
|
|
232
|
+
spanId: SPAN_ID,
|
|
233
|
+
},
|
|
234
|
+
])
|
|
235
|
+
)
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it.each([
|
|
239
|
+
['no getActiveSpan on the host', createMockInstance],
|
|
240
|
+
['no active span', () => createMockInstance({ getActiveSpan: () => null })],
|
|
241
|
+
['an unsampled span', () => withActiveSpan(`00-${TRACE_ID}-${SPAN_ID}-00`)],
|
|
242
|
+
['a span with no traceparent', () => withActiveSpan(null)],
|
|
243
|
+
[
|
|
244
|
+
'a throwing host',
|
|
245
|
+
() =>
|
|
246
|
+
createMockInstance({
|
|
247
|
+
getActiveSpan: () => {
|
|
248
|
+
throw new Error('boom')
|
|
249
|
+
},
|
|
250
|
+
}),
|
|
251
|
+
],
|
|
252
|
+
])('records the sample without an exemplar for %s', async (_, makeInstance) => {
|
|
253
|
+
const instance = makeInstance()
|
|
254
|
+
const metrics = createMetrics(undefined, instance)
|
|
255
|
+
metrics.count('c', 2)
|
|
256
|
+
await metrics.flush()
|
|
257
|
+
|
|
258
|
+
const [point] = dataPoints(instance)
|
|
259
|
+
expect(point.asDouble).toBe(2)
|
|
260
|
+
expect(point).not.toHaveProperty('exemplars')
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
it('keeps the exemplar of a window merged back after a failed flush', async () => {
|
|
264
|
+
const instance = withActiveSpan(`00-${TRACE_ID}-${SPAN_ID}-01`)
|
|
265
|
+
instance._sendMetricsBatch
|
|
266
|
+
.mockResolvedValueOnce({ kind: 'retry-later', error: new Error('503') })
|
|
267
|
+
.mockResolvedValue({ kind: 'ok' })
|
|
268
|
+
const metrics = createMetrics(undefined, instance)
|
|
269
|
+
metrics.count('c', 1)
|
|
270
|
+
await metrics.flush()
|
|
271
|
+
instance.getActiveSpan = () => null
|
|
272
|
+
metrics.count('c', 2)
|
|
273
|
+
await metrics.flush()
|
|
274
|
+
|
|
275
|
+
const point = dataPoints(instance)[1]
|
|
276
|
+
expect(point.asDouble).toBe(3)
|
|
277
|
+
expect(point.exemplars[0]).toMatchObject({ traceId: TRACE_ID, spanId: SPAN_ID, asDouble: 1 })
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
|
|
206
281
|
describe('resource attributes', () => {
|
|
207
282
|
it('attaches service.name, sdk identity, and user resource attributes', async () => {
|
|
208
283
|
const metrics = createMetrics({
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
MetricAttributes,
|
|
4
4
|
MetricSample,
|
|
5
5
|
MetricType,
|
|
6
|
+
OtlpExemplar,
|
|
6
7
|
OtlpHistogramDataPoint,
|
|
7
8
|
OtlpMetric,
|
|
8
9
|
OtlpMetricsPayload,
|
|
@@ -14,6 +15,7 @@ import { FlushTimer } from '../utils/flush-timer'
|
|
|
14
15
|
import { RetryAfterWindow } from '../utils/retry-after'
|
|
15
16
|
import { MAX_FLUSH_BACKOFF_MS, NO_JITTER, backoffDelayMs, drawJitter } from '../utils/backoff'
|
|
16
17
|
import { toOtlpKeyValueList } from '../utils/otlp-any-value'
|
|
18
|
+
import { TRACE_FLAGS_SAMPLED, parseTraceparent } from '../traces/traceparent'
|
|
17
19
|
import {
|
|
18
20
|
DEFAULT_HISTOGRAM_BOUNDS,
|
|
19
21
|
bucketIndexFor,
|
|
@@ -26,6 +28,13 @@ import type { MetricsHost, ResolvedPostHogMetricsConfig } from './types'
|
|
|
26
28
|
|
|
27
29
|
const OTLP_TEMPORALITY_DELTA = 1
|
|
28
30
|
|
|
31
|
+
interface ExemplarState {
|
|
32
|
+
traceId: string
|
|
33
|
+
spanId: string
|
|
34
|
+
value: number
|
|
35
|
+
timeMs: number
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
interface HistogramState {
|
|
30
39
|
count: number
|
|
31
40
|
sum: number
|
|
@@ -47,6 +56,8 @@ interface SeriesState {
|
|
|
47
56
|
total?: number
|
|
48
57
|
last?: number
|
|
49
58
|
hist?: HistogramState
|
|
59
|
+
/** The last sample recorded inside a sampled span this window. */
|
|
60
|
+
exemplar?: ExemplarState
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
/**
|
|
@@ -62,6 +73,10 @@ interface SeriesState {
|
|
|
62
73
|
* Deliberately unlike logs, no per-user context (distinct ID, session ID) is
|
|
63
74
|
* attached: every attribute value creates a new series, and per-user series
|
|
64
75
|
* are the canonical metrics-cardinality explosion.
|
|
76
|
+
*
|
|
77
|
+
* A sample recorded inside a sampled span stamps its series with an exemplar
|
|
78
|
+
* (trace ID, span ID, value). One per series per window, last sample wins, so a
|
|
79
|
+
* metric point links to one representative trace at no cardinality cost.
|
|
65
80
|
*/
|
|
66
81
|
export class PostHogMetrics {
|
|
67
82
|
private _series = new Map<string, SeriesState>()
|
|
@@ -224,9 +239,29 @@ export class PostHogMetrics {
|
|
|
224
239
|
}
|
|
225
240
|
|
|
226
241
|
this._fold(state, filtered.value)
|
|
242
|
+
const traceContext = this._activeTraceContext()
|
|
243
|
+
if (traceContext) {
|
|
244
|
+
state.exemplar = { ...traceContext, value: filtered.value, timeMs: Date.now() }
|
|
245
|
+
}
|
|
227
246
|
this._armFlushTimer()
|
|
228
247
|
}
|
|
229
248
|
|
|
249
|
+
/**
|
|
250
|
+
* The sampled span a sample is recorded in. An unsampled span is never
|
|
251
|
+
* exported, so an exemplar pointing at it would link to a missing trace.
|
|
252
|
+
*/
|
|
253
|
+
private _activeTraceContext(): { traceId: string; spanId: string } | undefined {
|
|
254
|
+
try {
|
|
255
|
+
const parsed = parseTraceparent(this._instance.getActiveSpan?.()?.traceparent())
|
|
256
|
+
if (parsed && parsed.flags === TRACE_FLAGS_SAMPLED) {
|
|
257
|
+
return { traceId: parsed.traceId, spanId: parsed.spanId }
|
|
258
|
+
}
|
|
259
|
+
} catch {
|
|
260
|
+
// A throwing host never costs the sample itself.
|
|
261
|
+
}
|
|
262
|
+
return undefined
|
|
263
|
+
}
|
|
264
|
+
|
|
230
265
|
/**
|
|
231
266
|
* Cardinality gate for adding a series to the live window — warns once per
|
|
232
267
|
* window when the cap is hit. Applied on capture and on merge-back alike.
|
|
@@ -413,6 +448,7 @@ export class PostHogMetrics {
|
|
|
413
448
|
|
|
414
449
|
const attributes = toOtlpKeyValueList(state.attributes ?? {}, this._logger)
|
|
415
450
|
const startNano = msToUnixNano(state.windowStartMs)
|
|
451
|
+
const exemplars = toOtlpExemplars(state.exemplar)
|
|
416
452
|
|
|
417
453
|
if (state.type === 'count') {
|
|
418
454
|
const dp: OtlpNumberDataPoint = {
|
|
@@ -420,6 +456,7 @@ export class PostHogMetrics {
|
|
|
420
456
|
startTimeUnixNano: startNano,
|
|
421
457
|
timeUnixNano: nowNano,
|
|
422
458
|
asDouble: state.total ?? 0,
|
|
459
|
+
...exemplars,
|
|
423
460
|
}
|
|
424
461
|
metric.sum!.dataPoints.push(dp)
|
|
425
462
|
} else if (state.type === 'gauge') {
|
|
@@ -427,6 +464,7 @@ export class PostHogMetrics {
|
|
|
427
464
|
attributes,
|
|
428
465
|
timeUnixNano: nowNano,
|
|
429
466
|
asDouble: state.last ?? 0,
|
|
467
|
+
...exemplars,
|
|
430
468
|
}
|
|
431
469
|
metric.gauge!.dataPoints.push(dp)
|
|
432
470
|
} else if (state.hist) {
|
|
@@ -440,6 +478,7 @@ export class PostHogMetrics {
|
|
|
440
478
|
max: state.hist.max,
|
|
441
479
|
bucketCounts: state.hist.bucketCounts,
|
|
442
480
|
explicitBounds: DEFAULT_HISTOGRAM_BOUNDS,
|
|
481
|
+
...exemplars,
|
|
443
482
|
}
|
|
444
483
|
metric.histogram!.dataPoints.push(dp)
|
|
445
484
|
}
|
|
@@ -461,6 +500,8 @@ export class PostHogMetrics {
|
|
|
461
500
|
continue
|
|
462
501
|
}
|
|
463
502
|
current.windowStartMs = Math.min(current.windowStartMs, old.windowStartMs)
|
|
503
|
+
// The live window's exemplar is newer; the old one only fills a gap.
|
|
504
|
+
current.exemplar = current.exemplar ?? old.exemplar
|
|
464
505
|
switch (current.type) {
|
|
465
506
|
case 'count':
|
|
466
507
|
current.total = (current.total ?? 0) + (old.total ?? 0)
|
|
@@ -488,6 +529,25 @@ export class PostHogMetrics {
|
|
|
488
529
|
}
|
|
489
530
|
}
|
|
490
531
|
|
|
532
|
+
// Spread into the data point, so a point without an exemplar keeps its exact
|
|
533
|
+
// pre-exemplar wire shape.
|
|
534
|
+
function toOtlpExemplars(exemplar: ExemplarState | undefined): { exemplars?: OtlpExemplar[] } {
|
|
535
|
+
if (!exemplar) {
|
|
536
|
+
return {}
|
|
537
|
+
}
|
|
538
|
+
return {
|
|
539
|
+
exemplars: [
|
|
540
|
+
{
|
|
541
|
+
filteredAttributes: [],
|
|
542
|
+
timeUnixNano: msToUnixNano(exemplar.timeMs),
|
|
543
|
+
asDouble: exemplar.value,
|
|
544
|
+
traceId: exemplar.traceId,
|
|
545
|
+
spanId: exemplar.spanId,
|
|
546
|
+
},
|
|
547
|
+
],
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
491
551
|
export { buildOtlpMetricsPayload, buildMetricsResourceAttributes, DEFAULT_HISTOGRAM_BOUNDS } from './metrics-utils'
|
|
492
552
|
export { resolveMetricsConfig } from './config'
|
|
493
553
|
export type { MetricsHost, PostHogMetricsConfig, ResolvedPostHogMetricsConfig, SendMetricsBatchOutcome } from './types'
|
|
@@ -13,9 +13,10 @@ export type {
|
|
|
13
13
|
OtlpHistogramDataPoint,
|
|
14
14
|
OtlpMetric,
|
|
15
15
|
OtlpMetricsPayload,
|
|
16
|
+
OtlpExemplar,
|
|
16
17
|
} from '@posthog/types'
|
|
17
18
|
|
|
18
|
-
import type { BeforeSendMetricFn, MetricAttributeValue, OtlpMetricsPayload } from '@posthog/types'
|
|
19
|
+
import type { BeforeSendMetricFn, MetricAttributeValue, OtlpMetricsPayload, Span } from '@posthog/types'
|
|
19
20
|
|
|
20
21
|
/** Same tagged outcome shape as `SendLogsBatchOutcome` — one policy for both signals. */
|
|
21
22
|
export type SendMetricsBatchOutcome =
|
|
@@ -43,6 +44,11 @@ export interface MetricsHost {
|
|
|
43
44
|
_sendMetricsBatch(payload: OtlpMetricsPayload): Promise<SendMetricsBatchOutcome>
|
|
44
45
|
getLibraryId(): string
|
|
45
46
|
getLibraryVersion(): string
|
|
47
|
+
/**
|
|
48
|
+
* The span active where a sample is recorded. A sampled one stamps the
|
|
49
|
+
* sample's series with an exemplar. Hosts without tracing leave it out.
|
|
50
|
+
*/
|
|
51
|
+
getActiveSpan?(): Span | null
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/**
|
|
@@ -9,8 +9,10 @@ const SPAN_ID_BYTES = 8
|
|
|
9
9
|
const TRACE_ID_HEX = TRACE_ID_BYTES * 2
|
|
10
10
|
const SPAN_ID_HEX = SPAN_ID_BYTES * 2
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
// Spelled out rather than `'0'.repeat(...)`: this runs at module load and the
|
|
13
|
+
// browser bundle, which reaches it through metrics, still loads in IE11.
|
|
14
|
+
const INVALID_SPAN_ID = '0000000000000000'
|
|
15
|
+
const INVALID_TRACE_ID = INVALID_SPAN_ID + INVALID_SPAN_ID
|
|
14
16
|
|
|
15
17
|
const HEX_RE = /^[0-9a-f]+$/
|
|
16
18
|
|