@wizeworks/lens-cloud 0.3.0-alpha.1 → 0.3.0-alpha.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/README.md +58 -5
- package/dist/alerts/evaluate.d.ts.map +1 -1
- package/dist/alerts/evaluate.js +20 -6
- package/dist/alerts/evaluate.js.map +1 -1
- package/dist/alerts/notify.d.ts +13 -2
- package/dist/alerts/notify.d.ts.map +1 -1
- package/dist/alerts/notify.js +22 -16
- package/dist/alerts/notify.js.map +1 -1
- package/dist/app.d.ts +16 -2
- package/dist/app.d.ts.map +1 -1
- package/dist/auth/auth.d.ts +51 -0
- package/dist/auth/auth.d.ts.map +1 -0
- package/dist/auth/auth.js +63 -0
- package/dist/auth/auth.js.map +1 -0
- package/dist/auth/bridge.d.ts +7 -0
- package/dist/auth/bridge.d.ts.map +1 -0
- package/dist/auth/bridge.js +39 -0
- package/dist/auth/bridge.js.map +1 -0
- package/dist/auth/crypto.d.ts +0 -5
- package/dist/auth/crypto.d.ts.map +1 -1
- package/dist/auth/crypto.js +3 -20
- package/dist/auth/crypto.js.map +1 -1
- package/dist/auth/delete-user.d.ts +16 -0
- package/dist/auth/delete-user.d.ts.map +1 -0
- package/dist/auth/delete-user.js +21 -0
- package/dist/auth/delete-user.js.map +1 -0
- package/dist/auth/deps.d.ts +27 -0
- package/dist/auth/deps.d.ts.map +1 -0
- package/dist/auth/deps.js +3 -0
- package/dist/auth/deps.js.map +1 -0
- package/dist/auth/email-token.d.ts +8 -0
- package/dist/auth/email-token.d.ts.map +1 -0
- package/dist/auth/email-token.js +15 -0
- package/dist/auth/email-token.js.map +1 -0
- package/dist/auth/hooks.d.ts +4 -0
- package/dist/auth/hooks.d.ts.map +1 -0
- package/dist/auth/hooks.js +143 -0
- package/dist/auth/hooks.js.map +1 -0
- package/dist/auth/join-scope.d.ts +7 -0
- package/dist/auth/join-scope.d.ts.map +1 -0
- package/dist/auth/join-scope.js +17 -0
- package/dist/auth/join-scope.js.map +1 -0
- package/dist/auth/options.d.ts +17 -0
- package/dist/auth/options.d.ts.map +1 -0
- package/dist/auth/options.js +98 -0
- package/dist/auth/options.js.map +1 -0
- package/dist/auth/password.d.ts +10 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +22 -0
- package/dist/auth/password.js.map +1 -0
- package/dist/auth/plugins.d.ts +4 -0
- package/dist/auth/plugins.d.ts.map +1 -0
- package/dist/auth/plugins.js +45 -0
- package/dist/auth/plugins.js.map +1 -0
- package/dist/auth/principal.d.ts +8 -3
- package/dist/auth/principal.d.ts.map +1 -1
- package/dist/auth/principal.js +13 -8
- package/dist/auth/principal.js.map +1 -1
- package/dist/auth/roles.d.ts +43 -3
- package/dist/auth/roles.d.ts.map +1 -1
- package/dist/auth/roles.js +15 -6
- package/dist/auth/roles.js.map +1 -1
- package/dist/auth/schema-names.d.ts +130 -0
- package/dist/auth/schema-names.d.ts.map +1 -0
- package/dist/auth/schema-names.js +53 -0
- package/dist/auth/schema-names.js.map +1 -0
- package/dist/auth/secret.d.ts +12 -0
- package/dist/auth/secret.d.ts.map +1 -0
- package/dist/auth/secret.js +32 -0
- package/dist/auth/secret.js.map +1 -0
- package/dist/auth/security-notices.d.ts +34 -0
- package/dist/auth/security-notices.d.ts.map +1 -0
- package/dist/auth/security-notices.js +81 -0
- package/dist/auth/security-notices.js.map +1 -0
- package/dist/auth/signup.d.ts +23 -0
- package/dist/auth/signup.d.ts.map +1 -0
- package/dist/auth/signup.js +61 -0
- package/dist/auth/signup.js.map +1 -0
- package/dist/auth/sso.d.ts +21 -0
- package/dist/auth/sso.d.ts.map +1 -0
- package/dist/auth/sso.js +35 -0
- package/dist/auth/sso.js.map +1 -0
- package/dist/auth/wire.d.ts +16 -0
- package/dist/auth/wire.d.ts.map +1 -0
- package/dist/auth/wire.js +47 -0
- package/dist/auth/wire.js.map +1 -0
- package/dist/changes.d.ts +15 -0
- package/dist/changes.d.ts.map +1 -0
- package/dist/changes.js +45 -0
- package/dist/changes.js.map +1 -0
- package/dist/cli-args.d.ts +1 -1
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +66 -14
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +22 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +30 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +37 -0
- package/dist/config.js.map +1 -1
- package/dist/copy-cli.d.ts +3 -0
- package/dist/copy-cli.d.ts.map +1 -0
- package/dist/copy-cli.js +24 -0
- package/dist/copy-cli.js.map +1 -0
- package/dist/db/db.d.ts +7 -2
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +28 -10
- package/dist/db/db.js.map +1 -1
- package/dist/db/migrate.d.ts +2 -2
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +15 -5
- package/dist/db/migrate.js.map +1 -1
- package/dist/db/schema-auth.d.ts +2 -0
- package/dist/db/schema-auth.d.ts.map +1 -0
- package/dist/db/schema-auth.js +93 -0
- package/dist/db/schema-auth.js.map +1 -0
- package/dist/db/schema-mail.d.ts +2 -0
- package/dist/db/schema-mail.d.ts.map +1 -0
- package/dist/db/schema-mail.js +8 -0
- package/dist/db/schema-mail.js.map +1 -0
- package/dist/db/schema-notify.d.ts +2 -0
- package/dist/db/schema-notify.d.ts.map +1 -0
- package/dist/db/schema-notify.js +26 -0
- package/dist/db/schema-notify.js.map +1 -0
- package/dist/db/schema-search.d.ts +2 -0
- package/dist/db/schema-search.d.ts.map +1 -0
- package/dist/db/schema-search.js +16 -0
- package/dist/db/schema-search.js.map +1 -0
- package/dist/db/schema-sso.d.ts +2 -0
- package/dist/db/schema-sso.d.ts.map +1 -0
- package/dist/db/schema-sso.js +17 -0
- package/dist/db/schema-sso.js.map +1 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +10 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/db/trigram.d.ts +4 -0
- package/dist/db/trigram.d.ts.map +1 -0
- package/dist/db/trigram.js +34 -0
- package/dist/db/trigram.js.map +1 -0
- package/dist/http/http.d.ts +2 -0
- package/dist/http/http.d.ts.map +1 -1
- package/dist/http/http.js +7 -3
- package/dist/http/http.js.map +1 -1
- package/dist/jobs.d.ts +1 -1
- package/dist/jobs.d.ts.map +1 -1
- package/dist/jobs.js +23 -11
- package/dist/jobs.js.map +1 -1
- package/dist/mail/blocks.d.ts +14 -0
- package/dist/mail/blocks.d.ts.map +1 -0
- package/dist/mail/blocks.js +35 -0
- package/dist/mail/blocks.js.map +1 -0
- package/dist/mail/content.d.ts +68 -0
- package/dist/mail/content.d.ts.map +1 -0
- package/dist/mail/content.js +6 -0
- package/dist/mail/content.js.map +1 -0
- package/dist/mail/emails-digest.d.ts +10 -0
- package/dist/mail/emails-digest.d.ts.map +1 -0
- package/dist/mail/emails-digest.js +55 -0
- package/dist/mail/emails-digest.js.map +1 -0
- package/dist/mail/emails-health.d.ts +6 -0
- package/dist/mail/emails-health.d.ts.map +1 -0
- package/dist/mail/emails-health.js +36 -0
- package/dist/mail/emails-health.js.map +1 -0
- package/dist/mail/emails-security.d.ts +14 -0
- package/dist/mail/emails-security.d.ts.map +1 -0
- package/dist/mail/emails-security.js +27 -0
- package/dist/mail/emails-security.js.map +1 -0
- package/dist/mail/emails-team.d.ts +11 -0
- package/dist/mail/emails-team.d.ts.map +1 -0
- package/dist/mail/emails-team.js +45 -0
- package/dist/mail/emails-team.js.map +1 -0
- package/dist/mail/emails.d.ts +9 -0
- package/dist/mail/emails.d.ts.map +1 -0
- package/dist/mail/emails.js +49 -0
- package/dist/mail/emails.js.map +1 -0
- package/dist/mail/layout.d.ts +6 -0
- package/dist/mail/layout.d.ts.map +1 -0
- package/dist/mail/layout.js +10 -0
- package/dist/mail/layout.js.map +1 -0
- package/dist/mail/mailer.d.ts +25 -0
- package/dist/mail/mailer.d.ts.map +1 -0
- package/dist/mail/mailer.js +50 -0
- package/dist/mail/mailer.js.map +1 -0
- package/dist/mail/preview.d.ts +6 -0
- package/dist/mail/preview.d.ts.map +1 -0
- package/dist/mail/preview.js +26 -0
- package/dist/mail/preview.js.map +1 -0
- package/dist/mail/resend.d.ts +13 -0
- package/dist/mail/resend.d.ts.map +1 -0
- package/dist/mail/resend.js +34 -0
- package/dist/mail/resend.js.map +1 -0
- package/dist/mail/samples.d.ts +3 -0
- package/dist/mail/samples.d.ts.map +1 -0
- package/dist/mail/samples.js +63 -0
- package/dist/mail/samples.js.map +1 -0
- package/dist/mail/stop-route.d.ts +4 -0
- package/dist/mail/stop-route.d.ts.map +1 -0
- package/dist/mail/stop-route.js +41 -0
- package/dist/mail/stop-route.js.map +1 -0
- package/dist/mail/svix.d.ts +8 -0
- package/dist/mail/svix.d.ts.map +1 -0
- package/dist/mail/svix.js +17 -0
- package/dist/mail/svix.js.map +1 -0
- package/dist/mail/templates.d.ts +12 -0
- package/dist/mail/templates.d.ts.map +1 -0
- package/dist/mail/templates.js +18 -0
- package/dist/mail/templates.js.map +1 -0
- package/dist/mail/text.d.ts +4 -0
- package/dist/mail/text.d.ts.map +1 -0
- package/dist/mail/text.js +17 -0
- package/dist/mail/text.js.map +1 -0
- package/dist/mail/theme.d.ts +32 -0
- package/dist/mail/theme.d.ts.map +1 -0
- package/dist/mail/theme.js +27 -0
- package/dist/mail/theme.js.map +1 -0
- package/dist/mail/unsubscribe.d.ts +14 -0
- package/dist/mail/unsubscribe.d.ts.map +1 -0
- package/dist/mail/unsubscribe.js +39 -0
- package/dist/mail/unsubscribe.js.map +1 -0
- package/dist/mail/webhook.d.ts +5 -0
- package/dist/mail/webhook.d.ts.map +1 -0
- package/dist/mail/webhook.js +41 -0
- package/dist/mail/webhook.js.map +1 -0
- package/dist/notify/digest-data.d.ts +32 -0
- package/dist/notify/digest-data.d.ts.map +1 -0
- package/dist/notify/digest-data.js +31 -0
- package/dist/notify/digest-data.js.map +1 -0
- package/dist/notify/digest.d.ts +17 -0
- package/dist/notify/digest.d.ts.map +1 -0
- package/dist/notify/digest.js +76 -0
- package/dist/notify/digest.js.map +1 -0
- package/dist/notify/health.d.ts +6 -0
- package/dist/notify/health.d.ts.map +1 -0
- package/dist/notify/health.js +42 -0
- package/dist/notify/health.js.map +1 -0
- package/dist/notify/team-describe.d.ts +22 -0
- package/dist/notify/team-describe.d.ts.map +1 -0
- package/dist/notify/team-describe.js +67 -0
- package/dist/notify/team-describe.js.map +1 -0
- package/dist/notify/team.d.ts +6 -0
- package/dist/notify/team.d.ts.map +1 -0
- package/dist/notify/team.js +56 -0
- package/dist/notify/team.js.map +1 -0
- package/dist/repo/alerts.d.ts +6 -2
- package/dist/repo/alerts.d.ts.map +1 -1
- package/dist/repo/alerts.js.map +1 -1
- package/dist/repo/auth-prune.d.ts +4 -0
- package/dist/repo/auth-prune.d.ts.map +1 -0
- package/dist/repo/auth-prune.js +8 -0
- package/dist/repo/auth-prune.js.map +1 -0
- package/dist/repo/mail-prefs.d.ts +35 -0
- package/dist/repo/mail-prefs.d.ts.map +1 -0
- package/dist/repo/mail-prefs.js +34 -0
- package/dist/repo/mail-prefs.js.map +1 -0
- package/dist/repo/orgs.d.ts +15 -25
- package/dist/repo/orgs.d.ts.map +1 -1
- package/dist/repo/orgs.js +18 -60
- package/dist/repo/orgs.js.map +1 -1
- package/dist/repo/services.d.ts +6 -0
- package/dist/repo/services.d.ts.map +1 -0
- package/dist/repo/services.js +16 -0
- package/dist/repo/services.js.map +1 -0
- package/dist/repo/suppressions.d.ts +8 -0
- package/dist/repo/suppressions.d.ts.map +1 -0
- package/dist/repo/suppressions.js +16 -0
- package/dist/repo/suppressions.js.map +1 -0
- package/dist/repo/trace-join.d.ts +9 -0
- package/dist/repo/trace-join.d.ts.map +1 -0
- package/dist/repo/trace-join.js +35 -0
- package/dist/repo/trace-join.js.map +1 -0
- package/dist/repo/trace-read.d.ts +6 -13
- package/dist/repo/trace-read.d.ts.map +1 -1
- package/dist/repo/trace-read.js +8 -3
- package/dist/repo/trace-read.js.map +1 -1
- package/dist/repo/trace-write.d.ts +5 -1
- package/dist/repo/trace-write.d.ts.map +1 -1
- package/dist/repo/trace-write.js +11 -2
- package/dist/repo/trace-write.js.map +1 -1
- package/dist/repo/users.d.ts +5 -16
- package/dist/repo/users.d.ts.map +1 -1
- package/dist/repo/users.js +2 -60
- package/dist/repo/users.js.map +1 -1
- package/dist/routes/alerts.d.ts.map +1 -1
- package/dist/routes/alerts.js +23 -6
- package/dist/routes/alerts.js.map +1 -1
- package/dist/routes/changes.d.ts +4 -0
- package/dist/routes/changes.d.ts.map +1 -0
- package/dist/routes/changes.js +19 -0
- package/dist/routes/changes.js.map +1 -0
- package/dist/routes/data.d.ts.map +1 -1
- package/dist/routes/data.js +24 -9
- package/dist/routes/data.js.map +1 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +8 -2
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/ingest.d.ts.map +1 -1
- package/dist/routes/ingest.js +7 -2
- package/dist/routes/ingest.js.map +1 -1
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +42 -25
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/me.d.ts +4 -0
- package/dist/routes/me.d.ts.map +1 -0
- package/dist/routes/me.js +37 -0
- package/dist/routes/me.js.map +1 -0
- package/dist/routes/metrics.d.ts +2 -2
- package/dist/routes/metrics.d.ts.map +1 -1
- package/dist/routes/metrics.js +2 -3
- package/dist/routes/metrics.js.map +1 -1
- package/dist/routes/models.d.ts +2 -0
- package/dist/routes/models.d.ts.map +1 -1
- package/dist/routes/models.js +10 -5
- package/dist/routes/models.js.map +1 -1
- package/dist/routes/notify.d.ts +4 -0
- package/dist/routes/notify.d.ts.map +1 -0
- package/dist/routes/notify.js +55 -0
- package/dist/routes/notify.js.map +1 -0
- package/dist/routes/orgs.d.ts.map +1 -1
- package/dist/routes/orgs.js +34 -53
- package/dist/routes/orgs.js.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +5 -3
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/search.d.ts +4 -0
- package/dist/routes/search.d.ts.map +1 -0
- package/dist/routes/search.js +33 -0
- package/dist/routes/search.js.map +1 -0
- package/dist/routes/shares.d.ts.map +1 -1
- package/dist/routes/shares.js +8 -5
- package/dist/routes/shares.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +59 -16
- package/dist/server.js.map +1 -1
- package/dist/settle.d.ts +7 -6
- package/dist/settle.d.ts.map +1 -1
- package/dist/settle.js +30 -13
- package/dist/settle.js.map +1 -1
- package/dist/telemetry/cached.d.ts +11 -0
- package/dist/telemetry/cached.d.ts.map +1 -0
- package/dist/telemetry/cached.js +30 -0
- package/dist/telemetry/cached.js.map +1 -0
- package/dist/telemetry/ch/admin.d.ts +10 -0
- package/dist/telemetry/ch/admin.d.ts.map +1 -0
- package/dist/telemetry/ch/admin.js +65 -0
- package/dist/telemetry/ch/admin.js.map +1 -0
- package/dist/telemetry/ch/http.d.ts +19 -0
- package/dist/telemetry/ch/http.d.ts.map +1 -0
- package/dist/telemetry/ch/http.js +91 -0
- package/dist/telemetry/ch/http.js.map +1 -0
- package/dist/telemetry/ch/metrics.d.ts +10 -0
- package/dist/telemetry/ch/metrics.d.ts.map +1 -0
- package/dist/telemetry/ch/metrics.js +61 -0
- package/dist/telemetry/ch/metrics.js.map +1 -0
- package/dist/telemetry/ch/queries.d.ts +19 -0
- package/dist/telemetry/ch/queries.d.ts.map +1 -0
- package/dist/telemetry/ch/queries.js +30 -0
- package/dist/telemetry/ch/queries.js.map +1 -0
- package/dist/telemetry/ch/queue.d.ts +34 -0
- package/dist/telemetry/ch/queue.d.ts.map +1 -0
- package/dist/telemetry/ch/queue.js +79 -0
- package/dist/telemetry/ch/queue.js.map +1 -0
- package/dist/telemetry/ch/read.d.ts +12 -0
- package/dist/telemetry/ch/read.d.ts.map +1 -0
- package/dist/telemetry/ch/read.js +72 -0
- package/dist/telemetry/ch/read.js.map +1 -0
- package/dist/telemetry/ch/schema-facts.d.ts +6 -0
- package/dist/telemetry/ch/schema-facts.d.ts.map +1 -0
- package/dist/telemetry/ch/schema-facts.js +49 -0
- package/dist/telemetry/ch/schema-facts.js.map +1 -0
- package/dist/telemetry/ch/schema-raw.d.ts +8 -0
- package/dist/telemetry/ch/schema-raw.d.ts.map +1 -0
- package/dist/telemetry/ch/schema-raw.js +35 -0
- package/dist/telemetry/ch/schema-raw.js.map +1 -0
- package/dist/telemetry/ch/schema-rollups.d.ts +2 -0
- package/dist/telemetry/ch/schema-rollups.d.ts.map +1 -0
- package/dist/telemetry/ch/schema-rollups.js +61 -0
- package/dist/telemetry/ch/schema-rollups.js.map +1 -0
- package/dist/telemetry/ch/schema.d.ts +12 -0
- package/dist/telemetry/ch/schema.d.ts.map +1 -0
- package/dist/telemetry/ch/schema.js +25 -0
- package/dist/telemetry/ch/schema.js.map +1 -0
- package/dist/telemetry/ch/settle-rows.d.ts +13 -0
- package/dist/telemetry/ch/settle-rows.d.ts.map +1 -0
- package/dist/telemetry/ch/settle-rows.js +67 -0
- package/dist/telemetry/ch/settle-rows.js.map +1 -0
- package/dist/telemetry/ch/settle.d.ts +7 -0
- package/dist/telemetry/ch/settle.d.ts.map +1 -0
- package/dist/telemetry/ch/settle.js +96 -0
- package/dist/telemetry/ch/settle.js.map +1 -0
- package/dist/telemetry/ch/store.d.ts +16 -0
- package/dist/telemetry/ch/store.d.ts.map +1 -0
- package/dist/telemetry/ch/store.js +65 -0
- package/dist/telemetry/ch/store.js.map +1 -0
- package/dist/telemetry/ch/util.d.ts +20 -0
- package/dist/telemetry/ch/util.d.ts.map +1 -0
- package/dist/telemetry/ch/util.js +45 -0
- package/dist/telemetry/ch/util.js.map +1 -0
- package/dist/telemetry/ch/write.d.ts +11 -0
- package/dist/telemetry/ch/write.d.ts.map +1 -0
- package/dist/telemetry/ch/write.js +59 -0
- package/dist/telemetry/ch/write.js.map +1 -0
- package/dist/telemetry/copy.d.ts +9 -0
- package/dist/telemetry/copy.d.ts.map +1 -0
- package/dist/telemetry/copy.js +60 -0
- package/dist/telemetry/copy.js.map +1 -0
- package/dist/telemetry/index.d.ts +11 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +21 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/pg-store.d.ts +5 -0
- package/dist/telemetry/pg-store.d.ts.map +1 -0
- package/dist/telemetry/pg-store.js +78 -0
- package/dist/telemetry/pg-store.js.map +1 -0
- package/dist/telemetry/store.d.ts +74 -0
- package/dist/telemetry/store.d.ts.map +1 -0
- package/dist/telemetry/store.js +2 -0
- package/dist/telemetry/store.js.map +1 -0
- package/package.json +20 -6
- package/dist/routes/auth.d.ts +0 -4
- package/dist/routes/auth.d.ts.map +0 -1
- package/dist/routes/auth.js +0 -106
- package/dist/routes/auth.js.map +0 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Metric rollups on ClickHouse: the same series state and tier rows as Postgres, merged by the tables instead of upserts.
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { groupMetricSeries, mergeStoredHists, metricBatchWrites, metricHistOfColumns, METRIC_SERIES_COLUMNS, METRIC_TIER_COLUMNS, metricSeriesValues, metricStateOfColumns, metricTierValues, seriesKeyOf, TIERS, } from "@wizeworks/lens-core";
|
|
4
|
+
import { nextVer, rowOf } from "./util.js";
|
|
5
|
+
const sha1 = (text) => createHash("sha1").update(text).digest("hex");
|
|
6
|
+
const cols = (list) => list.map((c) => (c === "project" ? "project_id" : c));
|
|
7
|
+
const TIER_INPUT = [
|
|
8
|
+
"project_id String, env String, series_key String, name String, bucket_ms Float64, cnt Float64, vsum Float64, vmin Nullable(Float64)",
|
|
9
|
+
"vmax Nullable(Float64), first_ms Float64, first_v Nullable(Float64), last_ms Float64, last_v Nullable(Float64), rate_delta Float64, rate_ms Float64",
|
|
10
|
+
"h_count Float64, h_sum Float64, h_min Nullable(Float64), h_max Nullable(Float64), h_bounds Nullable(String), h_counts Nullable(String), ver UInt64, expire_ms Float64",
|
|
11
|
+
].join(", ");
|
|
12
|
+
/** Sums add, extremes keep extremes, first and last follow time, and histogram counts follow the newest write that had some. */
|
|
13
|
+
const tierInsert = (table) => `${table}_t SELECT project_id, env, series_key, name, bucket_ms, sum(cnt), sum(vsum), min(vmin), max(vmax),
|
|
14
|
+
min(first_ms), argMinState(first_v, first_ms), max(last_ms), argMaxState(last_v, last_ms), sum(rate_delta), sum(rate_ms), sum(h_count), sum(h_sum),
|
|
15
|
+
min(h_min), max(h_max), argMaxState(h_bounds, ver), argMaxState(h_counts, ver), max(expire_ms) FROM input('${TIER_INPUT}')
|
|
16
|
+
GROUP BY project_id, env, series_key, name, bucket_ms`;
|
|
17
|
+
/** Stored histograms of the buckets this batch adds counts to. */
|
|
18
|
+
async function storedHists(ch, project, env, tiers) {
|
|
19
|
+
const stored = new Map();
|
|
20
|
+
for (const tier of TIERS) {
|
|
21
|
+
const mine = tiers.filter((t) => t.tier === tier && t.row.hist);
|
|
22
|
+
if (!mine.length)
|
|
23
|
+
continue;
|
|
24
|
+
const sql = `SELECT series_key, bucket_ms, h_count, h_sum, h_min, h_max, h_bounds, h_counts FROM metric_${tier.name}
|
|
25
|
+
WHERE project_id = {p1:String} AND env = {p2:String} AND has({p3:Array(String)}, series_key) AND has({p4:Array(Float64)}, bucket_ms) AND h_count > 0`;
|
|
26
|
+
const rows = await ch.query(sql, [project, env, [...new Set(mine.map((t) => t.key))], [...new Set(mine.map((t) => t.bucket))]]);
|
|
27
|
+
for (const r of rows)
|
|
28
|
+
stored.set(`${tier.name} ${r.series_key} ${Number(r.bucket_ms)}`, metricHistOfColumns(r));
|
|
29
|
+
}
|
|
30
|
+
return (t) => stored.get(`${t.tier.name} ${t.key} ${t.bucket}`) ?? null;
|
|
31
|
+
}
|
|
32
|
+
async function writeOnce(ch, project, env, points, now, retentionMs) {
|
|
33
|
+
const groups = groupMetricSeries(points, (p) => sha1(seriesKeyOf(p)));
|
|
34
|
+
const states = await ch.query("SELECT series_key, last_ms, last_value, last_hist FROM metric_series WHERE project_id = {p1:String} AND env = {p2:String} AND has({p3:Array(String)}, series_key)", [project, env, [...groups.keys()]]);
|
|
35
|
+
const { series, tiers } = metricBatchWrites(groups, new Map(states.map((r) => [String(r.series_key), metricStateOfColumns(r)])), now);
|
|
36
|
+
mergeStoredHists(tiers, await storedHists(ch, project, env, tiers));
|
|
37
|
+
const ver = nextVer(now);
|
|
38
|
+
const tierCols = cols(METRIC_TIER_COLUMNS);
|
|
39
|
+
for (const tier of TIERS) {
|
|
40
|
+
const rows = tiers.filter((t) => t.tier === tier).map((t) => ({ ...rowOf(tierCols, metricTierValues("ch", project, env, t)), ver, expire_ms: t.bucket + retentionMs }));
|
|
41
|
+
await ch.insert(tierInsert(`metric_${tier.name}`), rows);
|
|
42
|
+
}
|
|
43
|
+
const seriesRows = series.map((s) => ({ ...rowOf(cols(METRIC_SERIES_COLUMNS), metricSeriesValues("ch", project, env, s)), ver, expire_ms: s.state.lastMs + retentionMs }));
|
|
44
|
+
await ch.insert("metric_series_t", seriesRows);
|
|
45
|
+
}
|
|
46
|
+
/** Metric writes one at a time: each reads the series state it then advances. */
|
|
47
|
+
export class MetricWriter {
|
|
48
|
+
ch;
|
|
49
|
+
chain = Promise.resolve();
|
|
50
|
+
constructor(ch) {
|
|
51
|
+
this.ch = ch;
|
|
52
|
+
}
|
|
53
|
+
write(project, env, points, now, retentionMs) {
|
|
54
|
+
if (!points.length)
|
|
55
|
+
return Promise.resolve();
|
|
56
|
+
const run = this.chain.then(() => writeOnce(this.ch, project, env, points, now, retentionMs));
|
|
57
|
+
this.chain = run.catch(() => undefined);
|
|
58
|
+
return run;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../../src/telemetry/ch/metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TimeWindow } from "@wizeworks/lens-core";
|
|
2
|
+
import type { ChClient } from "./http.js";
|
|
3
|
+
/** Traces and spans of a project. */
|
|
4
|
+
export declare function counts(ch: ChClient, projectId: string): Promise<{
|
|
5
|
+
traces: number;
|
|
6
|
+
spans: number;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function traceEnvs(ch: ChClient, projectId: string): Promise<string[]>;
|
|
9
|
+
/** Distinct hours with a trace start in (from, to]. */
|
|
10
|
+
export declare function activeHours(ch: ChClient, projectId: string, from: number, to: number): Promise<number>;
|
|
11
|
+
/** The newest trace start per project, over the last month (older projects count as quiet). */
|
|
12
|
+
export declare function lastTraceMs(ch: ChClient, now: number): Promise<Map<string, number>>;
|
|
13
|
+
/** The slowest endpoints by p95 (interpolated, like Postgres percentile_cont) with at least `minCount` requests. */
|
|
14
|
+
export declare function slowestEndpoints(ch: ChClient, projectId: string, w: TimeWindow, minCount: number, limit: number): Promise<{
|
|
15
|
+
endpoint: string;
|
|
16
|
+
p95Ms: number;
|
|
17
|
+
count: number;
|
|
18
|
+
}[]>;
|
|
19
|
+
//# sourceMappingURL=queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/telemetry/ch/queries.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAI1C,qCAAqC;AACrC,wBAAsB,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAIxG;AAED,wBAAsB,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAElF;AAED,uDAAuD;AACvD,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO5G;AAED,+FAA+F;AAC/F,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAOzF;AAED,oHAAoH;AACpH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;;;;KAQrH"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const MONTH_MS = 30 * 86_400_000;
|
|
2
|
+
/** Traces and spans of a project. */
|
|
3
|
+
export async function counts(ch, projectId) {
|
|
4
|
+
const [t] = await ch.query("SELECT uniqExact(trace_id) AS n FROM trace_heads WHERE project_id = {p1:String}", [projectId]);
|
|
5
|
+
const [s] = await ch.query("SELECT count() AS n FROM spans_raw FINAL WHERE project_id = {p1:String}", [projectId]);
|
|
6
|
+
return { traces: Number(t?.n ?? 0), spans: Number(s?.n ?? 0) };
|
|
7
|
+
}
|
|
8
|
+
export async function traceEnvs(ch, projectId) {
|
|
9
|
+
return (await ch.query("SELECT DISTINCT env FROM trace_heads WHERE project_id = {p1:String}", [projectId])).map((r) => r.env);
|
|
10
|
+
}
|
|
11
|
+
/** Distinct hours with a trace start in (from, to]. */
|
|
12
|
+
export async function activeHours(ch, projectId, from, to) {
|
|
13
|
+
const [row] = await ch.query(`SELECT uniqExact(intDiv(toInt64(s), 3600000)) AS n FROM (SELECT min(start_ms) AS s FROM trace_heads WHERE project_id = {p1:String}
|
|
14
|
+
AND start_ms <= {p3:Float64} GROUP BY trace_id) WHERE s > {p2:Float64} AND s <= {p3:Float64}`, [projectId, from, to]);
|
|
15
|
+
return Number(row?.n ?? 0);
|
|
16
|
+
}
|
|
17
|
+
/** The newest trace start per project, over the last month (older projects count as quiet). */
|
|
18
|
+
export async function lastTraceMs(ch, now) {
|
|
19
|
+
const rows = await ch.query(`SELECT project_id, max(s) AS s FROM (SELECT project_id, trace_id, min(start_ms) AS s FROM trace_heads WHERE start_ms > {p1:Float64}
|
|
20
|
+
GROUP BY project_id, trace_id) GROUP BY project_id`, [now - MONTH_MS]);
|
|
21
|
+
return new Map(rows.map((r) => [r.project_id, Number(r.s)]));
|
|
22
|
+
}
|
|
23
|
+
/** The slowest endpoints by p95 (interpolated, like Postgres percentile_cont) with at least `minCount` requests. */
|
|
24
|
+
export async function slowestEndpoints(ch, projectId, w, minCount, limit) {
|
|
25
|
+
const rows = await ch.query(`SELECT endpoint, quantileExactInclusive(0.95)(duration_ms) AS p95, count() AS n FROM fact_requests
|
|
26
|
+
WHERE project_id = {p1:String} AND start_ms >= {p2:Float64} AND start_ms < {p3:Float64} GROUP BY endpoint HAVING n >= {p4:Float64}
|
|
27
|
+
ORDER BY p95 DESC LIMIT ${Math.max(0, Math.floor(limit))}`, [projectId, w.from, w.to, minCount]);
|
|
28
|
+
return rows.map((r) => ({ endpoint: r.endpoint, p95Ms: Number(r.p95), count: Number(r.n) }));
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../../src/telemetry/ch/queries.ts"],"names":[],"mappings":"AAIA,MAAM,QAAQ,GAAG,EAAE,GAAG,UAAU,CAAC;AAEjC,qCAAqC;AACrC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,EAAY,EAAE,SAAiB;IAC1D,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK,CAAgB,iFAAiF,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAC1I,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK,CAAgB,yEAAyE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAClI,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAY,EAAE,SAAiB;IAC7D,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,CAAkB,qEAAqE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACjJ,CAAC;AAED,uDAAuD;AACvD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAY,EAAE,SAAiB,EAAE,IAAY,EAAE,EAAU;IACzF,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK,CAC1B;kGAC8F,EAC9F,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CACtB,CAAC;IACF,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,+FAA+F;AAC/F,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAY,EAAE,GAAW;IACzD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CACzB;wDACoD,EACpD,CAAC,GAAG,GAAG,QAAQ,CAAC,CACjB,CAAC;IACF,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,oHAAoH;AACpH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EAAY,EAAE,SAAiB,EAAE,CAAa,EAAE,QAAgB,EAAE,KAAa;IACpH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CACzB;;+BAE2B,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAC3D,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CACpC,CAAC;IACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/F,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ChClient } from "./http.js";
|
|
2
|
+
export interface Dirty {
|
|
3
|
+
project: string;
|
|
4
|
+
traceId: string;
|
|
5
|
+
env: string;
|
|
6
|
+
/** The newest write. */
|
|
7
|
+
updatedMs: number;
|
|
8
|
+
/** When it last settled; 0 when never. */
|
|
9
|
+
settledMs: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class SettleQueue {
|
|
12
|
+
private readonly items;
|
|
13
|
+
/** Keys a settle batch holds, so an overlapping batch skips them. */
|
|
14
|
+
private readonly busy;
|
|
15
|
+
/** A trace got new parts. */
|
|
16
|
+
touch(project: string, traceId: string, env: string, now: number): void;
|
|
17
|
+
/** Traces quiet for a while, or busy ones not settled for long: newest first. */
|
|
18
|
+
due(now: number, limit: number): Dirty[];
|
|
19
|
+
/** Due traces for one batch, held until settled or released. Copies, so a write that lands meanwhile keeps its trace dirty. */
|
|
20
|
+
take(now: number, limit: number): Dirty[];
|
|
21
|
+
/** A failed batch: its traces wait for the next run. */
|
|
22
|
+
release(items: readonly Dirty[]): void;
|
|
23
|
+
/** Settled as of `updatedMs`: done unless something newer came in since. */
|
|
24
|
+
settled(d: Dirty, updatedMs: number): void;
|
|
25
|
+
/** How many traces of a project (optionally one environment) still wait. */
|
|
26
|
+
count(project: string, env?: string): number;
|
|
27
|
+
clear(project?: string): void;
|
|
28
|
+
get size(): number;
|
|
29
|
+
/** On start: traces written lately that never settled (or changed after), from the update log. */
|
|
30
|
+
recover(ch: ChClient, now: number): Promise<number>;
|
|
31
|
+
/** Every trace (after the facts version changed): its stats are rebuilt from scratch. */
|
|
32
|
+
requeueAll(ch: ChClient): Promise<number>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../../src/telemetry/ch/queue.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;IAClD,qEAAqE;IACrE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAE1C,6BAA6B;IAC7B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAKtE;IAED,iFAAiF;IACjF,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAGvC;IAED,+HAA+H;IAC/H,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAIxC;IAED,wDAAwD;IACxD,OAAO,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,GAAG,IAAI,CAErC;IAED,4EAA4E;IAC5E,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAOzC;IAED,4EAA4E;IAC5E,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAI3C;IAED,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAE5B;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,kGAAkG;IAC5F,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASxD;IAED,yFAAyF;IACnF,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9C;CACF"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const QUIET_MS = 5_000;
|
|
2
|
+
const BUSY_MS = 30_000;
|
|
3
|
+
const RECOVER_MS = 6 * 3_600_000;
|
|
4
|
+
export class SettleQueue {
|
|
5
|
+
items = new Map();
|
|
6
|
+
/** Keys a settle batch holds, so an overlapping batch skips them. */
|
|
7
|
+
busy = new Set();
|
|
8
|
+
/** A trace got new parts. */
|
|
9
|
+
touch(project, traceId, env, now) {
|
|
10
|
+
const k = `${project} ${traceId}`;
|
|
11
|
+
const it = this.items.get(k);
|
|
12
|
+
if (it)
|
|
13
|
+
(it.updatedMs = now), (it.env ||= env);
|
|
14
|
+
else
|
|
15
|
+
this.items.set(k, { project, traceId, env, updatedMs: now, settledMs: 0 });
|
|
16
|
+
}
|
|
17
|
+
/** Traces quiet for a while, or busy ones not settled for long: newest first. */
|
|
18
|
+
due(now, limit) {
|
|
19
|
+
const ready = [...this.items.entries()].filter(([k, d]) => !this.busy.has(k) && d.settledMs < d.updatedMs && (d.updatedMs <= now - QUIET_MS || d.settledMs <= now - BUSY_MS));
|
|
20
|
+
return ready.map(([, d]) => d).sort((a, b) => b.updatedMs - a.updatedMs).slice(0, limit);
|
|
21
|
+
}
|
|
22
|
+
/** Due traces for one batch, held until settled or released. Copies, so a write that lands meanwhile keeps its trace dirty. */
|
|
23
|
+
take(now, limit) {
|
|
24
|
+
const out = this.due(now, limit).map((d) => ({ ...d }));
|
|
25
|
+
for (const d of out)
|
|
26
|
+
this.busy.add(`${d.project} ${d.traceId}`);
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
/** A failed batch: its traces wait for the next run. */
|
|
30
|
+
release(items) {
|
|
31
|
+
for (const d of items)
|
|
32
|
+
this.busy.delete(`${d.project} ${d.traceId}`);
|
|
33
|
+
}
|
|
34
|
+
/** Settled as of `updatedMs`: done unless something newer came in since. */
|
|
35
|
+
settled(d, updatedMs) {
|
|
36
|
+
const k = `${d.project} ${d.traceId}`;
|
|
37
|
+
this.busy.delete(k);
|
|
38
|
+
const it = this.items.get(k);
|
|
39
|
+
if (!it)
|
|
40
|
+
return;
|
|
41
|
+
if (it.updatedMs <= updatedMs)
|
|
42
|
+
this.items.delete(k);
|
|
43
|
+
else
|
|
44
|
+
it.settledMs = updatedMs;
|
|
45
|
+
}
|
|
46
|
+
/** How many traces of a project (optionally one environment) still wait. */
|
|
47
|
+
count(project, env) {
|
|
48
|
+
let n = 0;
|
|
49
|
+
for (const d of this.items.values())
|
|
50
|
+
if (d.project === project && (!env || d.env === env))
|
|
51
|
+
n++;
|
|
52
|
+
return n;
|
|
53
|
+
}
|
|
54
|
+
clear(project) {
|
|
55
|
+
for (const [k, d] of this.items)
|
|
56
|
+
if (!project || d.project === project)
|
|
57
|
+
(this.items.delete(k), this.busy.delete(k));
|
|
58
|
+
}
|
|
59
|
+
get size() {
|
|
60
|
+
return this.items.size;
|
|
61
|
+
}
|
|
62
|
+
/** On start: traces written lately that never settled (or changed after), from the update log. */
|
|
63
|
+
async recover(ch, now) {
|
|
64
|
+
const rows = await ch.query(`SELECT u.project_id, u.trace_id, any(u.env) AS env, max(u.updated_ms) AS u, any(s.settled_ms) AS s FROM trace_updates u
|
|
65
|
+
LEFT JOIN (SELECT project_id, trace_id, settled_ms FROM settle_state FINAL) s ON s.project_id = u.project_id AND s.trace_id = u.trace_id
|
|
66
|
+
WHERE u.updated_ms > {p1:Float64} GROUP BY u.project_id, u.trace_id HAVING u > s`, [now - RECOVER_MS]);
|
|
67
|
+
for (const r of rows)
|
|
68
|
+
this.items.set(`${r.project_id} ${r.trace_id}`, { project: r.project_id, traceId: r.trace_id, env: r.env, updatedMs: r.u, settledMs: r.s });
|
|
69
|
+
return rows.length;
|
|
70
|
+
}
|
|
71
|
+
/** Every trace (after the facts version changed): its stats are rebuilt from scratch. */
|
|
72
|
+
async requeueAll(ch) {
|
|
73
|
+
const rows = await ch.query("SELECT project_id, trace_id, max(env) AS env, max(updated_ms) AS u FROM trace_heads GROUP BY project_id, trace_id");
|
|
74
|
+
for (const r of rows)
|
|
75
|
+
this.items.set(`${r.project_id} ${r.trace_id}`, { project: r.project_id, traceId: r.trace_id, env: r.env, updatedMs: r.u, settledMs: 0 });
|
|
76
|
+
return rows.length;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../../../src/telemetry/ch/queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Trace } from "@wizeworks/lens-core";
|
|
2
|
+
import type { TraceQuery } from "../store.js";
|
|
3
|
+
import type { ChClient } from "./http.js";
|
|
4
|
+
/** Newest traces that match, widening the lookback until enough are found. */
|
|
5
|
+
export declare function findTraceIds(ch: ChClient, t: TraceQuery, now: number): Promise<string[]>;
|
|
6
|
+
/** Whole traces of some projects, in the order of `ids`. Spans that two projects both sent count once. */
|
|
7
|
+
export declare function loadTraces(ch: ChClient, projects: readonly string[], ids: readonly string[]): Promise<Trace[]>;
|
|
8
|
+
/** One trace, or undefined when nothing of it is stored. */
|
|
9
|
+
export declare function getTrace(ch: ChClient, projects: readonly string[], traceId: string): Promise<Trace | undefined>;
|
|
10
|
+
/** The primary project's trace joined with its parts from `scope`; undefined when the primary project has none. */
|
|
11
|
+
export declare function joinedTrace(ch: ChClient, primaryId: string, scope: readonly string[], traceId: string): Promise<Trace | undefined>;
|
|
12
|
+
//# sourceMappingURL=read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/telemetry/ch/read.ts"],"names":[],"mappings":"AACA,OAAO,EAAyC,KAAK,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAwB1C,8EAA8E;AAC9E,wBAAsB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAM9F;AAWD,0GAA0G;AAC1G,wBAAsB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CASpH;AAED,4DAA4D;AAC5D,wBAAsB,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAGrH;AAED,mHAAmH;AACnH,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAIxI"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Trace reads on ClickHouse: lists from the bounds table, whole traces from the raw spans and logs.
|
|
2
|
+
import { buildTrace } from "@wizeworks/lens-core";
|
|
3
|
+
const CHUNK = 500;
|
|
4
|
+
/** Lists look back this far first, and further only when they find too few traces. */
|
|
5
|
+
const LOOKBACKS_MS = [3_600_000, 86_400_000, 7 * 86_400_000, Number.POSITIVE_INFINITY];
|
|
6
|
+
/** Trace ids, newest start first, for one lookback. Row filters narrow before grouping; HAVING checks the merged bounds. */
|
|
7
|
+
async function idsWithin(ch, t, now, backMs) {
|
|
8
|
+
const params = [t.projectId];
|
|
9
|
+
const p = (v, type) => (params.push(v), `{p${params.length}:${type}}`);
|
|
10
|
+
const rows = ["project_id = {p1:String}"];
|
|
11
|
+
if (Number.isFinite(backMs))
|
|
12
|
+
rows.push(`start_ms >= ${p(now - backMs, "Float64")}`);
|
|
13
|
+
if (t.since !== undefined)
|
|
14
|
+
rows.push(`updated_ms >= ${p(t.since, "Float64")}`);
|
|
15
|
+
if (t.before !== undefined)
|
|
16
|
+
rows.push(`start_ms < ${p(t.before, "Float64")}`);
|
|
17
|
+
if (t.session)
|
|
18
|
+
rows.push(`trace_id IN (SELECT trace_id FROM spans_raw WHERE project_id = {p1:String} AND session = ${p(t.session, "String")})`);
|
|
19
|
+
const having = ["1"];
|
|
20
|
+
if (t.from !== undefined)
|
|
21
|
+
having.push(`s >= ${p(t.from, "Float64")}`);
|
|
22
|
+
if (t.before !== undefined)
|
|
23
|
+
having.push(`s < ${p(t.before, "Float64")}`);
|
|
24
|
+
if (t.env)
|
|
25
|
+
having.push(`e = ${p(t.env, "String")}`);
|
|
26
|
+
const sql = `SELECT trace_id, min(start_ms) AS s, max(env) AS e FROM trace_heads WHERE ${rows.join(" AND ")} GROUP BY trace_id
|
|
27
|
+
HAVING ${having.join(" AND ")} ORDER BY s DESC, trace_id LIMIT ${Math.max(1, Math.floor(t.limit))}`;
|
|
28
|
+
return (await ch.query(sql, params)).map((r) => r.trace_id);
|
|
29
|
+
}
|
|
30
|
+
/** Newest traces that match, widening the lookback until enough are found. */
|
|
31
|
+
export async function findTraceIds(ch, t, now) {
|
|
32
|
+
for (const back of LOOKBACKS_MS) {
|
|
33
|
+
const ids = await idsWithin(ch, t, now, back);
|
|
34
|
+
if (ids.length >= t.limit || !Number.isFinite(back))
|
|
35
|
+
return ids;
|
|
36
|
+
}
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
async function jsonOf(ch, table, projects, ids) {
|
|
40
|
+
const out = new Map();
|
|
41
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
42
|
+
const sql = `SELECT trace_id, json FROM ${table} FINAL WHERE has({p1:Array(String)}, project_id) AND has({p2:Array(String)}, trace_id)`;
|
|
43
|
+
for (const r of await ch.query(sql, [projects, ids.slice(i, i + CHUNK)]))
|
|
44
|
+
out.set(r.trace_id, [...(out.get(r.trace_id) ?? []), r.json]);
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
/** Whole traces of some projects, in the order of `ids`. Spans that two projects both sent count once. */
|
|
49
|
+
export async function loadTraces(ch, projects, ids) {
|
|
50
|
+
if (ids.length === 0)
|
|
51
|
+
return [];
|
|
52
|
+
const [spans, logs] = await Promise.all([jsonOf(ch, "spans_raw", projects, ids), jsonOf(ch, "logs_raw", projects, ids)]);
|
|
53
|
+
return ids.map((id) => {
|
|
54
|
+
const seen = new Set();
|
|
55
|
+
const s = (spans.get(id) ?? []).map((j) => JSON.parse(j)).filter((x) => !seen.has(x.spanId) && seen.add(x.spanId));
|
|
56
|
+
const l = (logs.get(id) ?? []).map((j) => JSON.parse(j)).sort((a, b) => a.timeMs - b.timeMs);
|
|
57
|
+
return buildTrace(id, s, l, []);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/** One trace, or undefined when nothing of it is stored. */
|
|
61
|
+
export async function getTrace(ch, projects, traceId) {
|
|
62
|
+
const [t] = await loadTraces(ch, projects, [traceId]);
|
|
63
|
+
return t && t.spanCount + t.logs.length > 0 ? t : undefined;
|
|
64
|
+
}
|
|
65
|
+
/** The primary project's trace joined with its parts from `scope`; undefined when the primary project has none. */
|
|
66
|
+
export async function joinedTrace(ch, primaryId, scope, traceId) {
|
|
67
|
+
const own = await getTrace(ch, [primaryId], traceId);
|
|
68
|
+
if (!own || scope.every((id) => id === primaryId))
|
|
69
|
+
return own;
|
|
70
|
+
return getTrace(ch, [...new Set([primaryId, ...scope])], traceId);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/telemetry/ch/read.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const FACT_DDL: readonly string[];
|
|
2
|
+
/** Changes to shipped fact tables, in order. The n-gram bloom filled up at 8,192 rows a block and skipped nothing; the text index lists each block's n-grams. */
|
|
3
|
+
export declare const FACT_ALTERS: readonly string[];
|
|
4
|
+
/** Fact tables (storage names) and the columns that identify a row within a trace, for tombstones. */
|
|
5
|
+
export declare const FACT_KEYS: Record<string, readonly string[]>;
|
|
6
|
+
//# sourceMappingURL=schema-facts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-facts.d.ts","sourceRoot":"","sources":["../../../src/telemetry/ch/schema-facts.ts"],"names":[],"mappings":"AA+BA,eAAO,MAAM,QAAQ,EAAE,SAAS,MAAM,EASrC,CAAC;AAEF,iKAAiK;AACjK,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAGxC,CAAC;AAEF,sGAAsG;AACtG,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAOvD,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// ClickHouse fact tables (one row per request, trace, log line, slow span, search document, attribute), and views with the Postgres names.
|
|
2
|
+
import { EXPIRE, monthOf } from "./schema-raw.js";
|
|
3
|
+
const P = "project_id LowCardinality(String), trace_id String";
|
|
4
|
+
const VERSIONED = "ver UInt64, is_deleted UInt8, expire_ms Float64";
|
|
5
|
+
/** A fact table: replaced by version, deleted by tombstone; the view reads only live rows, with the Postgres columns. */
|
|
6
|
+
function fact(name, cols, order, time, indexes = "") {
|
|
7
|
+
const names = cols.split(/,\s*/).map((c) => c.trim().split(/\s+/)[0]);
|
|
8
|
+
return [
|
|
9
|
+
`CREATE TABLE IF NOT EXISTS ${name}_t (${P}, ${cols}, ${VERSIONED}${indexes ? `, ${indexes}` : ""})
|
|
10
|
+
ENGINE = ReplacingMergeTree(ver, is_deleted) PARTITION BY ${monthOf(time)} ORDER BY (${order}) ${EXPIRE}`,
|
|
11
|
+
`CREATE OR REPLACE VIEW ${name} AS SELECT project_id, trace_id, ${names.join(", ")} FROM ${name}_t FINAL`,
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
const REQUEST_COLS = [
|
|
15
|
+
"env LowCardinality(String), start_ms Float64, method LowCardinality(String), path String, endpoint String, status Nullable(Int32)",
|
|
16
|
+
"status_class LowCardinality(String), failed Bool, dur_class LowCardinality(String), aborted Bool, duration_ms Float64, server_ms Nullable(Float64)",
|
|
17
|
+
"db_ms Float64, db_count Int32, fetch_count Int32, fetch_ms Float64, render_ms Nullable(Float64), network_ms Nullable(Float64)",
|
|
18
|
+
"service LowCardinality(String), services String, errors Int32, insights Int32, health LowCardinality(String), user_agent Nullable(String)",
|
|
19
|
+
"client_address Nullable(String), end_user Nullable(String), request_id Nullable(String), tags String, search String",
|
|
20
|
+
].join(", ");
|
|
21
|
+
const SEARCH_COLS = [
|
|
22
|
+
"kind LowCardinality(String), owner String, env LowCardinality(String), time_ms Float64, span_id Nullable(String), service String",
|
|
23
|
+
"name Nullable(String), method Nullable(String), path Nullable(String), route Nullable(String), status Nullable(Int32), outcome Nullable(String)",
|
|
24
|
+
"duration_ms Nullable(Float64), level_rank Nullable(Int16), category Nullable(String), span_kind Nullable(String), end_user Nullable(String)",
|
|
25
|
+
"error Bool, message Nullable(String), text String",
|
|
26
|
+
].join(", ");
|
|
27
|
+
export const FACT_DDL = [
|
|
28
|
+
...fact("fact_requests", REQUEST_COLS, "project_id, start_ms, trace_id", "start_ms"),
|
|
29
|
+
...fact("fact_traces", "env LowCardinality(String), start_ms Float64, path String, duration_ms Float64, health Nullable(String), status String, services String, span_count Int32, slow Bool, search String", "project_id, start_ms, trace_id", "start_ms"),
|
|
30
|
+
...fact("fact_logs", "idx Int32, env LowCardinality(String), time_ms Float64, level LowCardinality(String), level_rank Int16, service LowCardinality(String), category String, message String, trace_name String, span_id Nullable(String), attributes String, search String", "project_id, time_ms, trace_id, idx", "time_ms"),
|
|
31
|
+
...fact("fact_critical", "span_id String, env LowCardinality(String), start_ms Float64, duration_ms Float64, name String, service LowCardinality(String), layer LowCardinality(String)", "project_id, start_ms, trace_id, span_id", "start_ms"),
|
|
32
|
+
...fact("fact_search", SEARCH_COLS, "project_id, kind, time_ms, trace_id, owner", "time_ms", "INDEX ix_text text TYPE ngrambf_v1(3, 65536, 2, 0) GRANULARITY 1, INDEX ix_trace trace_id TYPE bloom_filter GRANULARITY 1"),
|
|
33
|
+
...fact("fact_attrs", "src LowCardinality(String), owner String, key LowCardinality(String), value String, num Nullable(Float64), time_ms Float64", "project_id, key, value, trace_id, src, owner", "time_ms", "INDEX ix_trace trace_id TYPE bloom_filter GRANULARITY 1"),
|
|
34
|
+
];
|
|
35
|
+
/** Changes to shipped fact tables, in order. The n-gram bloom filled up at 8,192 rows a block and skipped nothing; the text index lists each block's n-grams. */
|
|
36
|
+
export const FACT_ALTERS = [
|
|
37
|
+
"ALTER TABLE fact_search_t ADD INDEX IF NOT EXISTS ix_text_ngrams text TYPE text(tokenizer = ngrams(3)) GRANULARITY 1",
|
|
38
|
+
"ALTER TABLE fact_search_t DROP INDEX IF EXISTS ix_text",
|
|
39
|
+
];
|
|
40
|
+
/** Fact tables (storage names) and the columns that identify a row within a trace, for tombstones. */
|
|
41
|
+
export const FACT_KEYS = {
|
|
42
|
+
fact_requests_t: ["start_ms"],
|
|
43
|
+
fact_traces_t: ["start_ms"],
|
|
44
|
+
fact_logs_t: ["time_ms", "idx"],
|
|
45
|
+
fact_critical_t: ["start_ms", "span_id"],
|
|
46
|
+
fact_search_t: ["kind", "time_ms", "owner"],
|
|
47
|
+
fact_attrs_t: ["key", "value", "src", "owner"],
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=schema-facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-facts.js","sourceRoot":"","sources":["../../../src/telemetry/ch/schema-facts.ts"],"names":[],"mappings":"AAAA,2IAA2I;AAC3I,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,CAAC,GAAG,oDAAoD,CAAC;AAC/D,MAAM,SAAS,GAAG,iDAAiD,CAAC;AAEpE,yHAAyH;AACzH,SAAS,IAAI,CAAC,IAAY,EAAE,IAAY,EAAE,KAAa,EAAE,IAAY,EAAE,OAAO,GAAG,EAAE;IACjF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;IACvE,OAAO;QACL,8BAA8B,IAAI,OAAO,CAAC,KAAK,IAAI,KAAK,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE;iEACpC,OAAO,CAAC,IAAI,CAAC,cAAc,KAAK,KAAK,MAAM,EAAE;QAC1G,0BAA0B,IAAI,oCAAoC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,UAAU;KAC1G,CAAC;AACJ,CAAC;AAED,MAAM,YAAY,GAAG;IACnB,mIAAmI;IACnI,oJAAoJ;IACpJ,+HAA+H;IAC/H,2IAA2I;IAC3I,qHAAqH;CACtH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,WAAW,GAAG;IAClB,kIAAkI;IAClI,iJAAiJ;IACjJ,6IAA6I;IAC7I,mDAAmD;CACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,MAAM,QAAQ,GAAsB;IACzC,GAAG,IAAI,CAAC,eAAe,EAAE,YAAY,EAAE,gCAAgC,EAAE,UAAU,CAAC;IACpF,GAAG,IAAI,CAAC,aAAa,EAAE,qLAAqL,EAAE,gCAAgC,EAAE,UAAU,CAAC;IAC3P,GAAG,IAAI,CAAC,WAAW,EAAE,wPAAwP,EAAE,oCAAoC,EAAE,SAAS,CAAC;IAC/T,GAAG,IAAI,CAAC,eAAe,EAAE,8JAA8J,EAAE,yCAAyC,EAAE,UAAU,CAAC;IAC/O,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,EAAE,4CAA4C,EAAE,SAAS,EACzF,2HAA2H,CAAC;IAC9H,GAAG,IAAI,CAAC,YAAY,EAAE,4HAA4H,EAAE,8CAA8C,EAAE,SAAS,EAC3M,yDAAyD,CAAC;CAC7D,CAAC;AAEF,iKAAiK;AACjK,MAAM,CAAC,MAAM,WAAW,GAAsB;IAC5C,sHAAsH;IACtH,wDAAwD;CACzD,CAAC;AAEF,sGAAsG;AACtG,MAAM,CAAC,MAAM,SAAS,GAAsC;IAC1D,eAAe,EAAE,CAAC,UAAU,CAAC;IAC7B,aAAa,EAAE,CAAC,UAAU,CAAC;IAC3B,WAAW,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC;IAC/B,eAAe,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC;IACxC,aAAa,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC;IAC3C,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC;CAC/C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Epoch ms in a column as a DateTime, for partitions and TTLs. */
|
|
2
|
+
export declare const secondsOf: (col: string) => string;
|
|
3
|
+
export declare const monthOf: (col: string) => string;
|
|
4
|
+
export declare const dayOf: (col: string) => string;
|
|
5
|
+
/** Rows go when their organization's retention runs out, set when they are written. */
|
|
6
|
+
export declare const EXPIRE: string;
|
|
7
|
+
export declare const RAW_TABLES: readonly string[];
|
|
8
|
+
//# sourceMappingURL=schema-raw.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-raw.d.ts","sourceRoot":"","sources":["../../../src/telemetry/ch/schema-raw.ts"],"names":[],"mappings":"AAEA,mEAAmE;AACnE,eAAO,MAAM,SAAS,QAAS,MAAM,KAAG,MAA2F,CAAC;AACpI,eAAO,MAAM,OAAO,QAAS,MAAM,KAAG,MAAuC,CAAC;AAC9E,eAAO,MAAM,KAAK,QAAS,MAAM,KAAG,MAAyC,CAAC;AAC9E,uFAAuF;AACvF,eAAO,MAAM,MAAM,QAAyC,CAAC;AAE7D,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EA0BvC,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// ClickHouse tables for what add-ons send: spans, logs, trace bounds, metric points, and the settle state.
|
|
2
|
+
/** Epoch ms in a column as a DateTime, for partitions and TTLs. */
|
|
3
|
+
export const secondsOf = (col) => `toDateTime(intDiv(toUInt64(least(greatest(${col}, 0.), 4102444800000.)), 1000))`;
|
|
4
|
+
export const monthOf = (col) => `toYYYYMM(${secondsOf(col)})`;
|
|
5
|
+
export const dayOf = (col) => `toYYYYMMDD(${secondsOf(col)})`;
|
|
6
|
+
/** Rows go when their organization's retention runs out, set when they are written. */
|
|
7
|
+
export const EXPIRE = `TTL ${secondsOf("expire_ms")} DELETE`;
|
|
8
|
+
export const RAW_TABLES = [
|
|
9
|
+
`CREATE TABLE IF NOT EXISTS spans_raw (
|
|
10
|
+
project_id LowCardinality(String), trace_id String, span_id String, service LowCardinality(String), start_ms Float64, duration_ms Float64,
|
|
11
|
+
session Nullable(String), json String CODEC(ZSTD(3)), ver UInt64, expire_ms Float64,
|
|
12
|
+
INDEX ix_session session TYPE bloom_filter GRANULARITY 4
|
|
13
|
+
) ENGINE = ReplacingMergeTree(ver) PARTITION BY ${monthOf("start_ms")} ORDER BY (project_id, trace_id, span_id) ${EXPIRE}`,
|
|
14
|
+
`CREATE TABLE IF NOT EXISTS logs_raw (
|
|
15
|
+
project_id LowCardinality(String), trace_id String, key String, time_ms Float64, json String CODEC(ZSTD(3)), ver UInt64, expire_ms Float64
|
|
16
|
+
) ENGINE = ReplacingMergeTree(ver) PARTITION BY ${monthOf("time_ms")} ORDER BY (project_id, trace_id, key) ${EXPIRE}`,
|
|
17
|
+
`CREATE TABLE IF NOT EXISTS trace_heads (
|
|
18
|
+
project_id LowCardinality(String), trace_id String, start_ms SimpleAggregateFunction(min, Float64), end_ms SimpleAggregateFunction(max, Float64),
|
|
19
|
+
updated_ms SimpleAggregateFunction(max, Float64), env SimpleAggregateFunction(max, String), expire_ms SimpleAggregateFunction(max, Float64)
|
|
20
|
+
) ENGINE = AggregatingMergeTree ORDER BY (project_id, trace_id) ${EXPIRE}`,
|
|
21
|
+
`CREATE TABLE IF NOT EXISTS trace_updates (
|
|
22
|
+
project_id LowCardinality(String), trace_id String, updated_ms Float64, env String
|
|
23
|
+
) ENGINE = MergeTree ORDER BY updated_ms TTL ${secondsOf("updated_ms")} + INTERVAL 2 DAY DELETE`,
|
|
24
|
+
`CREATE TABLE IF NOT EXISTS settle_state (
|
|
25
|
+
project_id LowCardinality(String), trace_id String, settled_ms Float64, contrib String CODEC(ZSTD(3)), ver UInt64, expire_ms Float64
|
|
26
|
+
) ENGINE = ReplacingMergeTree(ver) ORDER BY (project_id, trace_id) ${EXPIRE}`,
|
|
27
|
+
`CREATE TABLE IF NOT EXISTS metric_points_raw (
|
|
28
|
+
project_id LowCardinality(String), time_ms Float64, env LowCardinality(String), service LowCardinality(String), name LowCardinality(String),
|
|
29
|
+
series_key String, json String CODEC(ZSTD(3)), expire_ms Float64
|
|
30
|
+
) ENGINE = MergeTree PARTITION BY ${monthOf("time_ms")} ORDER BY (project_id, name, time_ms) ${EXPIRE}`,
|
|
31
|
+
`CREATE TABLE IF NOT EXISTS project_retention (
|
|
32
|
+
project_id String, days UInt32, ver UInt64
|
|
33
|
+
) ENGINE = ReplacingMergeTree(ver) ORDER BY project_id`,
|
|
34
|
+
];
|
|
35
|
+
//# sourceMappingURL=schema-raw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-raw.js","sourceRoot":"","sources":["../../../src/telemetry/ch/schema-raw.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAE3G,mEAAmE;AACnE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,6CAA6C,GAAG,iCAAiC,CAAC;AACpI,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,YAAY,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;AAC9E,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,cAAc,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;AAC9E,uFAAuF;AACvF,MAAM,CAAC,MAAM,MAAM,GAAG,OAAO,SAAS,CAAC,WAAW,CAAC,SAAS,CAAC;AAE7D,MAAM,CAAC,MAAM,UAAU,GAAsB;IAC3C;;;;oDAIkD,OAAO,CAAC,UAAU,CAAC,6CAA6C,MAAM,EAAE;IAC1H;;oDAEkD,OAAO,CAAC,SAAS,CAAC,yCAAyC,MAAM,EAAE;IACrH;;;oEAGkE,MAAM,EAAE;IAC1E;;iDAE+C,SAAS,CAAC,YAAY,CAAC,0BAA0B;IAChG;;uEAEqE,MAAM,EAAE;IAC7E;;;sCAGoC,OAAO,CAAC,SAAS,CAAC,yCAAyC,MAAM,EAAE;IACvG;;yDAEuD;CACxD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-rollups.d.ts","sourceRoot":"","sources":["../../../src/telemetry/ch/schema-rollups.ts"],"names":[],"mappings":"AAiEA,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAA8E,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// ClickHouse rollup, histogram, and metric tiers: rows add up when they merge, and views read them merged with the Postgres names.
|
|
2
|
+
import { IDS_MAX, TIERS } from "@wizeworks/lens-core";
|
|
3
|
+
import { dayOf, EXPIRE, monthOf, secondsOf } from "./schema-raw.js";
|
|
4
|
+
const sum = (c) => `${c} SimpleAggregateFunction(sum, Float64)`;
|
|
5
|
+
const COUNTERS = ["c0", "c1", "c2", "c3", "c4", "c5"];
|
|
6
|
+
/** Short tiers age out by bucket; the 1 h tier by retention. Day partitions for short tiers, month for 1 h. */
|
|
7
|
+
function tierTail(tier) {
|
|
8
|
+
const ttl = tier.keepMs === null ? EXPIRE : `TTL ${secondsOf("bucket_ms")} + INTERVAL ${Math.ceil(tier.keepMs / 1000)} SECOND DELETE`;
|
|
9
|
+
return `PARTITION BY ${tier.keepMs === null ? monthOf("bucket_ms") : dayOf("bucket_ms")} ${ttl}`;
|
|
10
|
+
}
|
|
11
|
+
function rollupDdl(tier) {
|
|
12
|
+
const t = tier.table;
|
|
13
|
+
const cols = [
|
|
14
|
+
"project_id LowCardinality(String), env LowCardinality(String), kind LowCardinality(String), key String, bucket_ms Float64",
|
|
15
|
+
...["n", "err", "sum_v", ...COUNTERS].map(sum),
|
|
16
|
+
"first_ms SimpleAggregateFunction(min, Float64), last_ms SimpleAggregateFunction(max, Float64), top_rank SimpleAggregateFunction(max, Float64)",
|
|
17
|
+
`top AggregateFunction(argMax, Nullable(String), Float64), ids AggregateFunction(groupArraySorted(${IDS_MAX}), Tuple(Float64, String))`,
|
|
18
|
+
"expire_ms SimpleAggregateFunction(max, Float64)",
|
|
19
|
+
].join(", ");
|
|
20
|
+
const read = ["project_id", "env", "kind", "key", "bucket_ms", "n", "err", "sum_v", ...COUNTERS, "first_ms", "last_ms", "top_rank"].join(", ");
|
|
21
|
+
const finals = "finalizeAggregation(top) AS top, arrayStringConcat(arrayMap(x -> x.2, finalizeAggregation(ids)), ' ') AS ids";
|
|
22
|
+
return [
|
|
23
|
+
`CREATE TABLE IF NOT EXISTS ${t}_t (${cols}) ENGINE = AggregatingMergeTree ORDER BY (project_id, kind, bucket_ms, env, key) ${tierTail(tier)}`,
|
|
24
|
+
`CREATE OR REPLACE VIEW ${t} AS SELECT ${read}, ${finals} FROM ${t}_t FINAL`,
|
|
25
|
+
`CREATE TABLE IF NOT EXISTS ${tier.hist}_t (
|
|
26
|
+
project_id LowCardinality(String), env LowCardinality(String), kind LowCardinality(String), key String, bucket_ms Float64, bin Int32,
|
|
27
|
+
cnt SimpleAggregateFunction(sum, Float64), expire_ms SimpleAggregateFunction(max, Float64)
|
|
28
|
+
) ENGINE = AggregatingMergeTree ORDER BY (project_id, kind, bucket_ms, env, key, bin) ${tierTail(tier)}`,
|
|
29
|
+
`CREATE OR REPLACE VIEW ${tier.hist} AS SELECT project_id, env, kind, key, bucket_ms, bin, cnt FROM ${tier.hist}_t FINAL`,
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
function metricDdl(tier) {
|
|
33
|
+
const t = `metric_${tier.name}`;
|
|
34
|
+
const nmin = (c) => `${c} SimpleAggregateFunction(min, Nullable(Float64))`;
|
|
35
|
+
const nmax = (c) => `${c} SimpleAggregateFunction(max, Nullable(Float64))`;
|
|
36
|
+
const cols = [
|
|
37
|
+
"project_id LowCardinality(String), env LowCardinality(String), series_key String, name LowCardinality(String), bucket_ms Float64",
|
|
38
|
+
sum("cnt"), sum("vsum"), nmin("vmin"), nmax("vmax"), "first_ms SimpleAggregateFunction(min, Float64)",
|
|
39
|
+
"first_v AggregateFunction(argMin, Nullable(Float64), Float64)", "last_ms SimpleAggregateFunction(max, Float64)",
|
|
40
|
+
"last_v AggregateFunction(argMax, Nullable(Float64), Float64)", sum("rate_delta"), sum("rate_ms"), sum("h_count"), sum("h_sum"), nmin("h_min"), nmax("h_max"),
|
|
41
|
+
"h_bounds AggregateFunction(argMax, Nullable(String), UInt64), h_counts AggregateFunction(argMax, Nullable(String), UInt64)",
|
|
42
|
+
"expire_ms SimpleAggregateFunction(max, Float64)",
|
|
43
|
+
].join(", ");
|
|
44
|
+
const read = "project_id, env, series_key, name, bucket_ms, cnt, vsum, vmin, vmax, first_ms, last_ms, rate_delta, rate_ms, h_count, h_sum, h_min, h_max";
|
|
45
|
+
const finals = ["first_v", "last_v", "h_bounds", "h_counts"].map((c) => `finalizeAggregation(${c}) AS ${c}`).join(", ");
|
|
46
|
+
return [
|
|
47
|
+
`CREATE TABLE IF NOT EXISTS ${t}_t (${cols}) ENGINE = AggregatingMergeTree ORDER BY (project_id, name, bucket_ms, env, series_key) ${tierTail(tier)}`,
|
|
48
|
+
`CREATE OR REPLACE VIEW ${t} AS SELECT ${read}, ${finals} FROM ${t}_t FINAL`,
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
const SERIES_DDL = [
|
|
52
|
+
`CREATE TABLE IF NOT EXISTS metric_series_t (
|
|
53
|
+
project_id LowCardinality(String), env LowCardinality(String), series_key String, name LowCardinality(String), service LowCardinality(String),
|
|
54
|
+
kind LowCardinality(String), unit String, description String, monotonic Bool, temporality String, attributes String, last_ms Float64,
|
|
55
|
+
last_value Nullable(Float64), last_hist Nullable(String), ver UInt64, expire_ms Float64
|
|
56
|
+
) ENGINE = ReplacingMergeTree(ver) ORDER BY (project_id, env, series_key) ${EXPIRE}`,
|
|
57
|
+
`CREATE OR REPLACE VIEW metric_series AS SELECT project_id, env, series_key, name, service, kind, unit, description, monotonic, temporality,
|
|
58
|
+
attributes, last_ms, last_value, last_hist FROM metric_series_t FINAL`,
|
|
59
|
+
];
|
|
60
|
+
export const ROLLUP_DDL = [...TIERS.flatMap(rollupDdl), ...TIERS.flatMap(metricDdl), ...SERIES_DDL];
|
|
61
|
+
//# sourceMappingURL=schema-rollups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-rollups.js","sourceRoot":"","sources":["../../../src/telemetry/ch/schema-rollups.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ChClient } from "./http.js";
|
|
2
|
+
/** Every statement, in order. A change to a shipped table needs an ALTER added here, never an edit to its CREATE. */
|
|
3
|
+
export declare const CH_SCHEMA: readonly string[];
|
|
4
|
+
/** Tables whose rows belong to one project, for clearing it. Views are left out. */
|
|
5
|
+
export declare const PROJECT_TABLES: readonly string[];
|
|
6
|
+
/** Every statement without its TTL clauses: for tests on a fixed clock, whose rows would expire on insert. */
|
|
7
|
+
export declare const withoutTtl: (sql: string) => string;
|
|
8
|
+
/** Create the database (through the default one) and every table and view. `ttl: false` keeps every row (tests only). */
|
|
9
|
+
export declare function migrateClickHouse(url: string, client: ChClient, o?: {
|
|
10
|
+
ttl?: boolean;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/telemetry/ch/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAY,MAAM,WAAW,CAAC;AAapD,qHAAqH;AACrH,eAAO,MAAM,SAAS,EAAE,SAAS,MAAM,EAAmG,CAAC;AAE3I,oFAAoF;AACpF,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAAgD,CAAC;AAE7F,8GAA8G;AAC9G,eAAO,MAAM,UAAU,QAAS,MAAM,KAAG,MAAmD,CAAC;AAE7F,yHAAyH;AACzH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/G"}
|