@obsunified/collector 2.0.1
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/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +9 -0
- package/dist/auth.js.map +1 -0
- package/dist/chunk-UGWDOGGH.js +319 -0
- package/dist/chunk-UGWDOGGH.js.map +1 -0
- package/dist/chunk-XKQTVIRE.js +671 -0
- package/dist/chunk-XKQTVIRE.js.map +1 -0
- package/dist/index.d.ts +1197 -0
- package/dist/index.js +17707 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest-auth-HFVO1zIp.d.ts +165 -0
- package/dist/openai-FJYOQ7WO.js +384 -0
- package/dist/openai-FJYOQ7WO.js.map +1 -0
- package/package.json +73 -0
- package/src/ai-parity/ai-parity.acceptance.test.ts +449 -0
- package/src/analyses/derive.ts +642 -0
- package/src/analyses/index.ts +50 -0
- package/src/analyses/investigations.ts +277 -0
- package/src/analyses/tier0.ts +568 -0
- package/src/auth/dashboard-auth.ts +269 -0
- package/src/auth/ingest-auth.ts +147 -0
- package/src/durable-objects/tail-hub.test.ts +32 -0
- package/src/durable-objects/tail-hub.ts +158 -0
- package/src/framework/collector.ts +467 -0
- package/src/framework/env.ts +90 -0
- package/src/framework/logger.ts +81 -0
- package/src/index.ts +211 -0
- package/src/lib/action-aggregates.ts +1031 -0
- package/src/lib/action-identity.ts +106 -0
- package/src/lib/actions-store.ts +397 -0
- package/src/lib/ai-pricing.ts +80 -0
- package/src/lib/ai-store/calls.ts +148 -0
- package/src/lib/ai-store/evaluations.test.ts +47 -0
- package/src/lib/ai-store/evaluations.ts +125 -0
- package/src/lib/ai-store/helpers.ts +37 -0
- package/src/lib/ai-store/retention.ts +17 -0
- package/src/lib/ai-store/sessions.ts +277 -0
- package/src/lib/ai-store/spans.ts +109 -0
- package/src/lib/ai-store/types.ts +112 -0
- package/src/lib/ai-store.ts +76 -0
- package/src/lib/alerts-store.ts +458 -0
- package/src/lib/analyses-runner.ts +439 -0
- package/src/lib/analyses-store.test.ts +243 -0
- package/src/lib/analyses-store.ts +454 -0
- package/src/lib/ask.test.ts +302 -0
- package/src/lib/ask.ts +390 -0
- package/src/lib/blob-store-s3.ts +213 -0
- package/src/lib/blob-store.ts +366 -0
- package/src/lib/eval-cases-store.test.ts +171 -0
- package/src/lib/eval-cases-store.ts +1033 -0
- package/src/lib/evidence-references.test.ts +10 -0
- package/src/lib/evidence-references.ts +684 -0
- package/src/lib/hash.ts +26 -0
- package/src/lib/identity-index/action-lookups.ts +805 -0
- package/src/lib/identity-index/constants.ts +1 -0
- package/src/lib/identity-index/key-lookups.ts +199 -0
- package/src/lib/identity-index/mappers.ts +349 -0
- package/src/lib/identity-index/types.ts +196 -0
- package/src/lib/identity-index/user-lookup.ts +137 -0
- package/src/lib/identity-index.test.ts +624 -0
- package/src/lib/identity-index.ts +85 -0
- package/src/lib/json.ts +39 -0
- package/src/lib/llm.ts +263 -0
- package/src/lib/logs-store.ts +188 -0
- package/src/lib/metrics-store.test.ts +189 -0
- package/src/lib/metrics-store.ts +312 -0
- package/src/lib/narrate-gate.test.ts +260 -0
- package/src/lib/narrate-gate.ts +253 -0
- package/src/lib/openai.test.ts +300 -0
- package/src/lib/openai.ts +512 -0
- package/src/lib/otlp.ts +212 -0
- package/src/lib/parse-pprof.test.ts +64 -0
- package/src/lib/parse-pprof.ts +184 -0
- package/src/lib/payload-capture.ts +22 -0
- package/src/lib/projects-store.ts +207 -0
- package/src/lib/propagation-metric.test.ts +196 -0
- package/src/lib/propagation-metric.ts +175 -0
- package/src/lib/sql-db-dialect.test.ts +22 -0
- package/src/lib/sql-db-postgres.ts +229 -0
- package/src/lib/sql-db.ts +166 -0
- package/src/lib/stage6.test.ts +216 -0
- package/src/lib/store/export.ts +65 -0
- package/src/lib/store/helpers.ts +367 -0
- package/src/lib/store/ingest.ts +68 -0
- package/src/lib/store/issues.ts +158 -0
- package/src/lib/store/overview.ts +127 -0
- package/src/lib/store/retention.ts +10 -0
- package/src/lib/store/service-map.ts +384 -0
- package/src/lib/store/trace-detail.bench.ts +76 -0
- package/src/lib/store/trace-detail.test.ts +410 -0
- package/src/lib/store/trace-detail.ts +427 -0
- package/src/lib/store/trace-queries.test.ts +29 -0
- package/src/lib/store/trace-queries.ts +89 -0
- package/src/lib/store-overview.test.ts +77 -0
- package/src/lib/store.ts +96 -0
- package/src/lib/tail-publisher.ts +64 -0
- package/src/lib/test-utils/mem-sql-db.test.ts +93 -0
- package/src/lib/test-utils/mem-sql-db.ts +86 -0
- package/src/lib/ua-parser.ts +61 -0
- package/src/lib/usage-store.ts +567 -0
- package/src/migrations/001_telemetry_spans.sql +28 -0
- package/src/migrations/002_usage_events.sql +24 -0
- package/src/migrations/003_usage_analytics_columns.sql +13 -0
- package/src/migrations/004_logs.sql +19 -0
- package/src/migrations/005_ai_calls.sql +25 -0
- package/src/migrations/006_user_profiles.sql +11 -0
- package/src/migrations/007_session_replay_metadata.sql +10 -0
- package/src/migrations/008_session_replay_storage_bytes.sql +1 -0
- package/src/migrations/009_projects_and_keys.sql +22 -0
- package/src/migrations/010_signal_project_id.sql +15 -0
- package/src/migrations/011_default_project_seed.sql +3 -0
- package/src/migrations/012_alert_rules.sql +17 -0
- package/src/migrations/013_alert_evaluations.sql +13 -0
- package/src/migrations/014_alert_state.sql +9 -0
- package/src/migrations/015_metrics.sql +58 -0
- package/src/migrations/016_metrics_exp_histogram_summary.sql +5 -0
- package/src/migrations/017_span_dropped_counts.sql +11 -0
- package/src/migrations/018_log_flags.sql +8 -0
- package/src/migrations/019_ai_span_payloads.sql +30 -0
- package/src/migrations/020_ai_span_evaluations.sql +33 -0
- package/src/migrations/021_ai_span_session.sql +13 -0
- package/src/migrations/022_span_log_session_id.sql +13 -0
- package/src/migrations/023_service_map_indexes.sql +32 -0
- package/src/migrations/024_analysis_results.sql +49 -0
- package/src/migrations/025_stage6_autopinning_alerts.sql +38 -0
- package/src/migrations/026_obs_dashboard_project_seed.sql +18 -0
- package/src/migrations/027_identity_propagation.sql +50 -0
- package/src/migrations/028_profile_blobs.sql +57 -0
- package/src/migrations/029_telemetry_sdk_name.sql +20 -0
- package/src/migrations/030_analysis_claim.sql +18 -0
- package/src/migrations/031_agent_action_graph.sql +154 -0
- package/src/migrations/032_payload_capture_flags.sql +8 -0
- package/src/migrations/033_eval_cases.sql +52 -0
- package/src/migrations/034_eval_case_results.sql +23 -0
- package/src/migrations/035_metric_exemplars.sql +33 -0
- package/src/migrations/036_trace_instrumentation_gaps.sql +19 -0
- package/src/migrations/037_eval_runs.sql +37 -0
- package/src/migrations/038_tool_call_evidence.sql +11 -0
- package/src/migrations/039_drop_trace_instrumentation_gaps.sql +11 -0
- package/src/migrations/040_evidence_retrieval_refs.sql +50 -0
- package/src/migrations-postgres/001_telemetry_spans.sql +33 -0
- package/src/migrations-postgres/002_usage_events.sql +24 -0
- package/src/migrations-postgres/003_usage_analytics_columns.sql +13 -0
- package/src/migrations-postgres/004_logs.sql +19 -0
- package/src/migrations-postgres/005_ai_calls.sql +25 -0
- package/src/migrations-postgres/006_user_profiles.sql +11 -0
- package/src/migrations-postgres/007_session_replay_metadata.sql +10 -0
- package/src/migrations-postgres/008_session_replay_storage_bytes.sql +2 -0
- package/src/migrations-postgres/009_projects_and_keys.sql +25 -0
- package/src/migrations-postgres/010_signal_project_id.sql +18 -0
- package/src/migrations-postgres/011_default_project_seed.sql +5 -0
- package/src/migrations-postgres/012_alert_rules.sql +17 -0
- package/src/migrations-postgres/013_alert_evaluations.sql +13 -0
- package/src/migrations-postgres/014_alert_state.sql +9 -0
- package/src/migrations-postgres/015_metrics.sql +47 -0
- package/src/migrations-postgres/016_metrics_exp_histogram_summary.sql +1 -0
- package/src/migrations-postgres/017_span_dropped_counts.sql +4 -0
- package/src/migrations-postgres/018_log_flags.sql +2 -0
- package/src/migrations-postgres/019_ai_span_payloads.sql +18 -0
- package/src/migrations-postgres/020_ai_span_evaluations.sql +21 -0
- package/src/migrations-postgres/021_ai_span_session.sql +7 -0
- package/src/migrations-postgres/022_span_log_session_id.sql +7 -0
- package/src/migrations-postgres/023_service_map_indexes.sql +9 -0
- package/src/migrations-postgres/024_analysis_results.sql +41 -0
- package/src/migrations-postgres/025_stage6_autopinning_alerts.sql +17 -0
- package/src/migrations-postgres/026_obs_dashboard_project_seed.sql +14 -0
- package/src/migrations-postgres/027_identity_propagation.sql +27 -0
- package/src/migrations-postgres/028_profile_blobs.sql +48 -0
- package/src/migrations-postgres/029_telemetry_sdk_name.sql +5 -0
- package/src/migrations-postgres/030_analysis_claim.sql +5 -0
- package/src/migrations-postgres/031_agent_action_graph.sql +190 -0
- package/src/migrations-postgres/032_payload_capture_flags.sql +8 -0
- package/src/migrations-postgres/033_eval_cases.sql +55 -0
- package/src/migrations-postgres/034_eval_case_results.sql +26 -0
- package/src/migrations-postgres/035_metric_exemplars.sql +31 -0
- package/src/migrations-postgres/036_trace_instrumentation_gaps.sql +19 -0
- package/src/migrations-postgres/037_eval_runs.sql +40 -0
- package/src/migrations-postgres/038_tool_call_evidence.sql +11 -0
- package/src/migrations-postgres/039_drop_trace_instrumentation_gaps.sql +11 -0
- package/src/migrations-postgres/040_evidence_retrieval_refs.sql +47 -0
- package/src/migrations-postgres/README.md +40 -0
- package/src/otlp/acceptance.test.ts +373 -0
- package/src/otlp/decode/body.ts +127 -0
- package/src/otlp/decode/logs.ts +96 -0
- package/src/otlp/decode/metrics.ts +402 -0
- package/src/otlp/decode/traces.ts +92 -0
- package/src/otlp/decode/values.ts +150 -0
- package/src/otlp/decode.test.ts +800 -0
- package/src/otlp/decode.ts +11 -0
- package/src/otlp/gen/opentelemetry/proto/collector/logs/v1/logs_service_pb.ts +132 -0
- package/src/otlp/gen/opentelemetry/proto/collector/metrics/v1/metrics_service_pb.ts +158 -0
- package/src/otlp/gen/opentelemetry/proto/collector/trace/v1/trace_service_pb.ts +158 -0
- package/src/otlp/gen/opentelemetry/proto/common/v1/common_pb.ts +289 -0
- package/src/otlp/gen/opentelemetry/proto/logs/v1/logs_pb.ts +397 -0
- package/src/otlp/gen/opentelemetry/proto/metrics/v1/metrics_pb.ts +1329 -0
- package/src/otlp/gen/opentelemetry/proto/resource/v1/resource_pb.ts +86 -0
- package/src/otlp/gen/opentelemetry/proto/trace/v1/trace_pb.ts +710 -0
- package/src/otlp/response.test.ts +158 -0
- package/src/otlp/response.ts +129 -0
- package/src/plugins/_context.ts +15 -0
- package/src/plugins/action-graph-processor/enrichers.ts +45 -0
- package/src/plugins/action-graph-processor/redaction.ts +84 -0
- package/src/plugins/action-graph-processor.test.ts +1023 -0
- package/src/plugins/action-graph-processor.ts +1172 -0
- package/src/plugins/action-routes.test.ts +716 -0
- package/src/plugins/action-routes.ts +343 -0
- package/src/plugins/ai-receiver.ts +254 -0
- package/src/plugins/ai-span-payloads-processor.test.ts +90 -0
- package/src/plugins/ai-span-payloads-processor.ts +180 -0
- package/src/plugins/alerts-evaluator.test.ts +91 -0
- package/src/plugins/alerts-evaluator.ts +328 -0
- package/src/plugins/alerts-routes.ts +101 -0
- package/src/plugins/analyses-routes.ts +138 -0
- package/src/plugins/ask-routes.ts +182 -0
- package/src/plugins/bot-filter.ts +19 -0
- package/src/plugins/connected-routes/manifest.ts +531 -0
- package/src/plugins/connected-routes.test.ts +1791 -0
- package/src/plugins/connected-routes.ts +1103 -0
- package/src/plugins/dashboard-routes.ts +41 -0
- package/src/plugins/default-span-enrichment.ts +92 -0
- package/src/plugins/eval-cases-routes.test.ts +391 -0
- package/src/plugins/eval-cases-routes.ts +529 -0
- package/src/plugins/evidence-retrieval-routes.benchmark.test.ts +245 -0
- package/src/plugins/evidence-retrieval-routes.test.ts +932 -0
- package/src/plugins/evidence-retrieval-routes.ts +2179 -0
- package/src/plugins/gen-ai-normalizer.test.ts +680 -0
- package/src/plugins/gen-ai-normalizer.ts +302 -0
- package/src/plugins/identity-receiver.ts +96 -0
- package/src/plugins/issue-enrichment.ts +132 -0
- package/src/plugins/issue-insights.ts +81 -0
- package/src/plugins/logs-receiver.ts +160 -0
- package/src/plugins/metrics-receiver.ts +91 -0
- package/src/plugins/onboarding-routes.ts +54 -0
- package/src/plugins/otlp-receiver.ts +124 -0
- package/src/plugins/platform-routes.ts +165 -0
- package/src/plugins/profile-routes.ts +468 -0
- package/src/plugins/projects-routes.ts +92 -0
- package/src/plugins/query-routes.ts +220 -0
- package/src/plugins/redaction-processor.ts +132 -0
- package/src/plugins/replay-query-routes.test.ts +38 -0
- package/src/plugins/replay-query-routes.ts +199 -0
- package/src/plugins/replay-receiver.ts +81 -0
- package/src/plugins/tail-routes.test.ts +47 -0
- package/src/plugins/tail-routes.ts +42 -0
- package/src/plugins/timeline-routes.ts +244 -0
- package/src/plugins/ua-enrichment.ts +27 -0
- package/src/plugins/usage-normalization.ts +46 -0
- package/src/plugins/usage-privacy.ts +55 -0
- package/src/plugins/usage-query-routes.ts +102 -0
- package/src/plugins/usage-receiver.ts +129 -0
- package/src/plugins/users-query-routes.ts +78 -0
- package/src/plugins/utm-enrichment.ts +36 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
name TEXT NOT NULL,
|
|
4
|
+
slug TEXT NOT NULL UNIQUE,
|
|
5
|
+
created_at TEXT NOT NULL
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_projects_slug ON projects (slug);
|
|
9
|
+
|
|
10
|
+
CREATE TABLE IF NOT EXISTS ingest_keys (
|
|
11
|
+
id TEXT PRIMARY KEY,
|
|
12
|
+
project_id TEXT NOT NULL,
|
|
13
|
+
key_hash TEXT NOT NULL UNIQUE,
|
|
14
|
+
key_prefix TEXT NOT NULL,
|
|
15
|
+
name TEXT NOT NULL,
|
|
16
|
+
created_at TEXT NOT NULL,
|
|
17
|
+
revoked_at TEXT,
|
|
18
|
+
FOREIGN KEY (project_id) REFERENCES projects(id)
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
CREATE INDEX IF NOT EXISTS idx_ingest_keys_project ON ingest_keys (project_id, revoked_at);
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_ingest_keys_hash ON ingest_keys (key_hash);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- Add project_id to every signal table. DEFAULT 'default' backfills existing rows.
|
|
2
|
+
ALTER TABLE telemetry_spans ADD COLUMN project_id TEXT NOT NULL DEFAULT 'default';
|
|
3
|
+
ALTER TABLE logs ADD COLUMN project_id TEXT NOT NULL DEFAULT 'default';
|
|
4
|
+
ALTER TABLE usage_events ADD COLUMN project_id TEXT NOT NULL DEFAULT 'default';
|
|
5
|
+
ALTER TABLE ai_calls ADD COLUMN project_id TEXT NOT NULL DEFAULT 'default';
|
|
6
|
+
ALTER TABLE session_replay_metadata ADD COLUMN project_id TEXT NOT NULL DEFAULT 'default';
|
|
7
|
+
ALTER TABLE user_profiles ADD COLUMN project_id TEXT NOT NULL DEFAULT 'default';
|
|
8
|
+
|
|
9
|
+
-- Composite indexes for project-scoped queries.
|
|
10
|
+
CREATE INDEX IF NOT EXISTS idx_spans_project_received ON telemetry_spans (project_id, received_at DESC);
|
|
11
|
+
CREATE INDEX IF NOT EXISTS idx_logs_project_received ON logs (project_id, received_at DESC);
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_usage_project_received ON usage_events (project_id, received_at DESC);
|
|
13
|
+
CREATE INDEX IF NOT EXISTS idx_ai_project_received ON ai_calls (project_id, received_at DESC);
|
|
14
|
+
CREATE INDEX IF NOT EXISTS idx_replay_project_last ON session_replay_metadata (project_id, last_chunk_at DESC);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_users_project_last ON user_profiles (project_id, last_seen_at DESC);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS alert_rules (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
project_id TEXT NOT NULL,
|
|
4
|
+
name TEXT NOT NULL,
|
|
5
|
+
signal TEXT NOT NULL,
|
|
6
|
+
query_json TEXT NOT NULL,
|
|
7
|
+
threshold REAL NOT NULL,
|
|
8
|
+
window_mins INTEGER NOT NULL,
|
|
9
|
+
comparison TEXT NOT NULL,
|
|
10
|
+
channels_json TEXT NOT NULL,
|
|
11
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
12
|
+
created_at TEXT NOT NULL,
|
|
13
|
+
updated_at TEXT NOT NULL,
|
|
14
|
+
FOREIGN KEY (project_id) REFERENCES projects(id)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_alert_rules_project ON alert_rules (project_id, enabled);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS alert_evaluations (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
rule_id TEXT NOT NULL,
|
|
4
|
+
project_id TEXT NOT NULL,
|
|
5
|
+
evaluated_at TEXT NOT NULL,
|
|
6
|
+
value REAL NOT NULL,
|
|
7
|
+
state TEXT NOT NULL,
|
|
8
|
+
notified INTEGER NOT NULL DEFAULT 0,
|
|
9
|
+
FOREIGN KEY (rule_id) REFERENCES alert_rules(id)
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_alert_eval_rule_time ON alert_evaluations (rule_id, evaluated_at DESC);
|
|
13
|
+
CREATE INDEX IF NOT EXISTS idx_alert_eval_project ON alert_evaluations (project_id, evaluated_at DESC);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS alert_state (
|
|
2
|
+
rule_id TEXT PRIMARY KEY,
|
|
3
|
+
project_id TEXT NOT NULL,
|
|
4
|
+
current_state TEXT NOT NULL,
|
|
5
|
+
last_state_change TEXT NOT NULL,
|
|
6
|
+
FOREIGN KEY (rule_id) REFERENCES alert_rules(id)
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
CREATE INDEX IF NOT EXISTS idx_alert_state_project ON alert_state (project_id);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
-- OTLP metrics storage.
|
|
2
|
+
--
|
|
3
|
+
-- Two tables:
|
|
4
|
+
-- metric_series — one row per unique (resource, scope, metric name, metric
|
|
5
|
+
-- attrs) tuple. Upserted on ingest.
|
|
6
|
+
-- metric_point — one row per datapoint. FK to metric_series.
|
|
7
|
+
--
|
|
8
|
+
-- Histogram-specific fields on metric_point are nullable (only populated for
|
|
9
|
+
-- type='histogram'). Gauge/sum write `value`. Exponential histograms and
|
|
10
|
+
-- Summary are not yet supported (Phase 5).
|
|
11
|
+
|
|
12
|
+
CREATE TABLE IF NOT EXISTS metric_series (
|
|
13
|
+
id TEXT PRIMARY KEY,
|
|
14
|
+
project_id TEXT NOT NULL,
|
|
15
|
+
name TEXT NOT NULL,
|
|
16
|
+
description TEXT,
|
|
17
|
+
unit TEXT,
|
|
18
|
+
type TEXT NOT NULL, -- 'gauge' | 'sum' | 'histogram'
|
|
19
|
+
is_monotonic INTEGER, -- 0/1 — sum only
|
|
20
|
+
temporality INTEGER, -- 1=DELTA, 2=CUMULATIVE — sum/histogram
|
|
21
|
+
scope_name TEXT,
|
|
22
|
+
scope_version TEXT,
|
|
23
|
+
service_name TEXT,
|
|
24
|
+
resource_attrs_json TEXT,
|
|
25
|
+
attributes_json TEXT,
|
|
26
|
+
identity TEXT NOT NULL, -- canonical JSON of identity tuple
|
|
27
|
+
created_at TEXT NOT NULL,
|
|
28
|
+
UNIQUE(project_id, identity)
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_metric_series_project_name
|
|
32
|
+
ON metric_series (project_id, name);
|
|
33
|
+
|
|
34
|
+
CREATE TABLE IF NOT EXISTS metric_point (
|
|
35
|
+
id TEXT PRIMARY KEY,
|
|
36
|
+
series_id TEXT NOT NULL,
|
|
37
|
+
project_id TEXT NOT NULL, -- denormalized for retention sweep
|
|
38
|
+
ts_ns TEXT NOT NULL, -- uint64 as decimal string
|
|
39
|
+
start_ts_ns TEXT,
|
|
40
|
+
value REAL, -- gauge/sum scalar
|
|
41
|
+
count INTEGER, -- histogram
|
|
42
|
+
sum REAL, -- histogram
|
|
43
|
+
min REAL, -- histogram
|
|
44
|
+
max REAL, -- histogram
|
|
45
|
+
bounds_json TEXT, -- histogram bucket upper bounds (number[])
|
|
46
|
+
bucket_counts_json TEXT, -- histogram bucket counts (number[])
|
|
47
|
+
exemplars_json TEXT, -- array of {value, traceId?, spanId?, tsNs}
|
|
48
|
+
received_at TEXT NOT NULL,
|
|
49
|
+
expires_at TEXT NOT NULL,
|
|
50
|
+
FOREIGN KEY (series_id) REFERENCES metric_series(id)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_metric_point_series_ts
|
|
54
|
+
ON metric_point (series_id, ts_ns);
|
|
55
|
+
CREATE INDEX IF NOT EXISTS idx_metric_point_expires
|
|
56
|
+
ON metric_point (expires_at);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_metric_point_project_received
|
|
58
|
+
ON metric_point (project_id, received_at DESC);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- Extend metric_point with a JSON blob for type-specific fields that don't
|
|
2
|
+
-- map cleanly onto columns: exponential histogram buckets (scale,
|
|
3
|
+
-- zeroCount, positive/negative) and summary quantileValues. Keeps the
|
|
4
|
+
-- schema compact without migrating whenever OTel adds a new metric type.
|
|
5
|
+
ALTER TABLE metric_point ADD COLUMN extra_json TEXT;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- OTLP span-level passthrough columns.
|
|
2
|
+
--
|
|
3
|
+
-- Matches RFC 0001 schema-conformance bar: droppedAttributesCount,
|
|
4
|
+
-- droppedEventsCount, droppedLinksCount, and W3C traceState must survive the
|
|
5
|
+
-- receiver end-to-end. Event/link-level dropped counts live inside
|
|
6
|
+
-- events_json / links_json already.
|
|
7
|
+
|
|
8
|
+
ALTER TABLE telemetry_spans ADD COLUMN trace_state TEXT;
|
|
9
|
+
ALTER TABLE telemetry_spans ADD COLUMN dropped_attributes_count INTEGER NOT NULL DEFAULT 0;
|
|
10
|
+
ALTER TABLE telemetry_spans ADD COLUMN dropped_events_count INTEGER NOT NULL DEFAULT 0;
|
|
11
|
+
ALTER TABLE telemetry_spans ADD COLUMN dropped_links_count INTEGER NOT NULL DEFAULT 0;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- OTLP log-record passthrough columns.
|
|
2
|
+
--
|
|
3
|
+
-- Matches RFC 0001 schema-conformance bar: LogRecord.flags (W3C trace
|
|
4
|
+
-- flags bitfield) and droppedAttributesCount must survive the receiver
|
|
5
|
+
-- end-to-end.
|
|
6
|
+
|
|
7
|
+
ALTER TABLE logs ADD COLUMN flags INTEGER NOT NULL DEFAULT 0;
|
|
8
|
+
ALTER TABLE logs ADD COLUMN dropped_attributes_count INTEGER NOT NULL DEFAULT 0;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-- Side table for large prompt/completion/tool/retrieval payloads attached
|
|
2
|
+
-- to OpenInference-kind spans (LLM/CHAIN/RETRIEVER/EMBEDDING/TOOL/AGENT/...).
|
|
3
|
+
--
|
|
4
|
+
-- Spans themselves continue to live in telemetry_spans — this table only
|
|
5
|
+
-- holds the input/output blobs that would otherwise bloat the hot spans
|
|
6
|
+
-- table. Keyed by (trace_id, span_id) so a join against telemetry_spans
|
|
7
|
+
-- reconstructs the full AI span.
|
|
8
|
+
--
|
|
9
|
+
-- Retention mirrors telemetry_spans: entries are purged when expires_at
|
|
10
|
+
-- elapses. span_kind is denormalized from attributes_json for cheap
|
|
11
|
+
-- filtering without json_extract.
|
|
12
|
+
|
|
13
|
+
CREATE TABLE IF NOT EXISTS ai_span_payloads (
|
|
14
|
+
project_id TEXT NOT NULL,
|
|
15
|
+
trace_id TEXT NOT NULL,
|
|
16
|
+
span_id TEXT NOT NULL,
|
|
17
|
+
span_kind TEXT NOT NULL,
|
|
18
|
+
input_json TEXT,
|
|
19
|
+
output_json TEXT,
|
|
20
|
+
received_at TEXT NOT NULL,
|
|
21
|
+
expires_at TEXT NOT NULL,
|
|
22
|
+
PRIMARY KEY (trace_id, span_id)
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
CREATE INDEX IF NOT EXISTS idx_ai_payloads_received
|
|
26
|
+
ON ai_span_payloads (received_at DESC);
|
|
27
|
+
CREATE INDEX IF NOT EXISTS idx_ai_payloads_project
|
|
28
|
+
ON ai_span_payloads (project_id, received_at DESC);
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_ai_payloads_kind
|
|
30
|
+
ON ai_span_payloads (project_id, span_kind, received_at DESC);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
-- Evaluations attached to an AI span. One span can have many evaluations
|
|
2
|
+
-- (e.g. an LLM-judge "hallucination" score plus a human "thumbs_up" label).
|
|
3
|
+
--
|
|
4
|
+
-- source tells us where the evaluation came from:
|
|
5
|
+
-- "llm_judge" — another model scored this span
|
|
6
|
+
-- "code" — deterministic check (regex, schema, etc.)
|
|
7
|
+
-- "human" — UI annotation / feedback
|
|
8
|
+
-- "user" — end-user thumbs up/down in the product
|
|
9
|
+
--
|
|
10
|
+
-- score is numeric (0..1 or any float); label is a free-form categorical
|
|
11
|
+
-- (e.g. "correct", "hallucinated", "👍"). Either or both may be set.
|
|
12
|
+
|
|
13
|
+
CREATE TABLE IF NOT EXISTS ai_span_evaluations (
|
|
14
|
+
evaluation_id TEXT PRIMARY KEY,
|
|
15
|
+
project_id TEXT NOT NULL,
|
|
16
|
+
trace_id TEXT NOT NULL,
|
|
17
|
+
span_id TEXT NOT NULL,
|
|
18
|
+
name TEXT NOT NULL,
|
|
19
|
+
score REAL,
|
|
20
|
+
label TEXT,
|
|
21
|
+
explanation TEXT,
|
|
22
|
+
source TEXT NOT NULL,
|
|
23
|
+
metadata_json TEXT,
|
|
24
|
+
created_at TEXT NOT NULL,
|
|
25
|
+
expires_at TEXT NOT NULL
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_ai_evals_span
|
|
29
|
+
ON ai_span_evaluations (trace_id, span_id);
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_ai_evals_project_created
|
|
31
|
+
ON ai_span_evaluations (project_id, created_at DESC);
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_ai_evals_project_name
|
|
33
|
+
ON ai_span_evaluations (project_id, name, created_at DESC);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- Denormalize session.id and user.id off the span's attributes_json into
|
|
2
|
+
-- ai_span_payloads so we can filter sessions / user threads cheaply without
|
|
3
|
+
-- a json_extract on every row.
|
|
4
|
+
--
|
|
5
|
+
-- Both columns are nullable — not every AI span belongs to a session.
|
|
6
|
+
|
|
7
|
+
ALTER TABLE ai_span_payloads ADD COLUMN session_id TEXT;
|
|
8
|
+
ALTER TABLE ai_span_payloads ADD COLUMN user_id TEXT;
|
|
9
|
+
|
|
10
|
+
CREATE INDEX IF NOT EXISTS idx_ai_payloads_session
|
|
11
|
+
ON ai_span_payloads (project_id, session_id, received_at DESC);
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_ai_payloads_user
|
|
13
|
+
ON ai_span_payloads (project_id, user_id, received_at DESC);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- Denormalize session.id off the span/log attributes so we can pivot from a
|
|
2
|
+
-- session to every telemetry signal (spans, logs) without a json_extract on
|
|
3
|
+
-- every row. Populated at ingest by the enrichment plugins.
|
|
4
|
+
--
|
|
5
|
+
-- Nullable — not every span or log belongs to a session.
|
|
6
|
+
|
|
7
|
+
ALTER TABLE telemetry_spans ADD COLUMN session_id TEXT;
|
|
8
|
+
ALTER TABLE logs ADD COLUMN session_id TEXT;
|
|
9
|
+
|
|
10
|
+
CREATE INDEX IF NOT EXISTS idx_spans_session
|
|
11
|
+
ON telemetry_spans (project_id, session_id, received_at DESC);
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_logs_session
|
|
13
|
+
ON logs (project_id, session_id, received_at DESC);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-- Service-map performance indices.
|
|
2
|
+
--
|
|
3
|
+
-- Two queries blow up at ~100k+ spans without these:
|
|
4
|
+
-- 1. The whole service-map endpoint filters by project_id + received_at
|
|
5
|
+
-- window, but the existing idx_spans_received_at is single-column
|
|
6
|
+
-- (received_at DESC) and can't prune on project_id, so multi-tenant
|
|
7
|
+
-- installs scan the world.
|
|
8
|
+
-- 2. The new async-edge query (added in 522424e) gates on
|
|
9
|
+
-- `links_json IS NOT NULL AND links_json != '[]'`. Without an index
|
|
10
|
+
-- that knows about that predicate, every row gets a json_each call
|
|
11
|
+
-- even when the column is NULL — order-of-magnitude slower than it
|
|
12
|
+
-- needs to be.
|
|
13
|
+
--
|
|
14
|
+
-- Both indices target (project_id, received_at DESC) as the leading
|
|
15
|
+
-- columns so range queries hit the index first and project filtering is
|
|
16
|
+
-- free. The partial index for links is much smaller than the full one
|
|
17
|
+
-- (links_json is non-empty on a small fraction of spans) so the planner
|
|
18
|
+
-- prefers it for the link-follow path.
|
|
19
|
+
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_spans_project_received
|
|
21
|
+
ON telemetry_spans (project_id, received_at DESC);
|
|
22
|
+
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_spans_with_links
|
|
24
|
+
ON telemetry_spans (project_id, received_at DESC)
|
|
25
|
+
WHERE links_json IS NOT NULL AND links_json != '[]';
|
|
26
|
+
|
|
27
|
+
-- Same scoping for service-name lookups: the per-service operations
|
|
28
|
+
-- query (used by the click-through drawer) filters by
|
|
29
|
+
-- (project_id, service_name, received_at). Existing idx_spans_service
|
|
30
|
+
-- is service_name-only.
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_spans_project_service_received
|
|
32
|
+
ON telemetry_spans (project_id, service_name, received_at DESC);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
-- RFC 0002 Stage 1: persistent storage for Analysis runs.
|
|
2
|
+
--
|
|
3
|
+
-- One row per (analysis_id, generated_at). The dashboard reads "latest result
|
|
4
|
+
-- per analysis" via the (project_id, analysis_id, generated_at DESC) index;
|
|
5
|
+
-- the retention cron drops rows past expires_at. Stage 1 only writes
|
|
6
|
+
-- status / primary / baseline / payload; narrative + narrative_signature
|
|
7
|
+
-- get filled by Stage 3.
|
|
8
|
+
|
|
9
|
+
CREATE TABLE IF NOT EXISTS analysis_definitions (
|
|
10
|
+
project_id TEXT NOT NULL,
|
|
11
|
+
id TEXT NOT NULL,
|
|
12
|
+
title TEXT NOT NULL,
|
|
13
|
+
"group" TEXT NOT NULL,
|
|
14
|
+
source TEXT NOT NULL, -- 'tier0' | 'tier1' | 'user' | 'llm-suggested'
|
|
15
|
+
view TEXT NOT NULL, -- 'tile' | 'page' | 'alert'
|
|
16
|
+
refresh_seconds INTEGER,
|
|
17
|
+
sql TEXT,
|
|
18
|
+
scope_json TEXT, -- JSON-serialized scope object
|
|
19
|
+
created_at TEXT NOT NULL,
|
|
20
|
+
updated_at TEXT NOT NULL,
|
|
21
|
+
last_run_at TEXT,
|
|
22
|
+
PRIMARY KEY (project_id, id)
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
CREATE INDEX IF NOT EXISTS idx_analysis_definitions_group
|
|
26
|
+
ON analysis_definitions (project_id, "group", id);
|
|
27
|
+
|
|
28
|
+
CREATE TABLE IF NOT EXISTS analysis_results (
|
|
29
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
30
|
+
project_id TEXT NOT NULL,
|
|
31
|
+
analysis_id TEXT NOT NULL,
|
|
32
|
+
generated_at INTEGER NOT NULL, -- unix epoch millis
|
|
33
|
+
params_hash TEXT,
|
|
34
|
+
status TEXT NOT NULL, -- 'ok' | 'warn' | 'critical' | 'unknown'
|
|
35
|
+
primary_value REAL,
|
|
36
|
+
baseline_value REAL,
|
|
37
|
+
delta_pct REAL,
|
|
38
|
+
payload_json TEXT NOT NULL,
|
|
39
|
+
narrative TEXT,
|
|
40
|
+
narrative_signature TEXT,
|
|
41
|
+
duration_ms INTEGER NOT NULL,
|
|
42
|
+
expires_at INTEGER NOT NULL -- unix epoch millis; matched by retention cron
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_analysis_results_latest
|
|
46
|
+
ON analysis_results (project_id, analysis_id, generated_at DESC);
|
|
47
|
+
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_analysis_results_expires
|
|
49
|
+
ON analysis_results (expires_at);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
-- RFC 0002 Stage 6: auto-pinning + alert→analysis binding.
|
|
2
|
+
--
|
|
3
|
+
-- Two coupled changes that share a migration so first-time installs land
|
|
4
|
+
-- in one shot:
|
|
5
|
+
--
|
|
6
|
+
-- 1. ask_evidence_events
|
|
7
|
+
-- Every time the Ask box's tool-use loop cites an analysis in its
|
|
8
|
+
-- answer, we drop a row here. The Health tab's "Pinned" group derives
|
|
9
|
+
-- from the top-cited analyses over the trailing 7 days. This is the
|
|
10
|
+
-- auto-pinning input — pure observation, no manual config required.
|
|
11
|
+
--
|
|
12
|
+
-- 2. alert_rules.analysis_id
|
|
13
|
+
-- Lets an alert rule reference an Analysis by id rather than carrying
|
|
14
|
+
-- its own query. The evaluator reads the analysis's latest primary
|
|
15
|
+
-- value; webhook payloads attach the analysis's current narrative so
|
|
16
|
+
-- Slack/PagerDuty messages are about *what's happening*, not just
|
|
17
|
+
-- "metric crossed threshold." NULL means the rule still uses its
|
|
18
|
+
-- `query_json` (the pre-Stage-6 path).
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS ask_evidence_events (
|
|
21
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
22
|
+
project_id TEXT NOT NULL,
|
|
23
|
+
analysis_id TEXT NOT NULL,
|
|
24
|
+
asked_at INTEGER NOT NULL -- unix epoch millis
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
CREATE INDEX IF NOT EXISTS idx_ask_evidence_events_recent
|
|
28
|
+
ON ask_evidence_events (project_id, asked_at DESC);
|
|
29
|
+
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_ask_evidence_events_analysis
|
|
31
|
+
ON ask_evidence_events (project_id, analysis_id, asked_at DESC);
|
|
32
|
+
|
|
33
|
+
-- ALTER TABLE ... ADD COLUMN is the single supported schema-change form
|
|
34
|
+
-- in SQLite/D1. Defaults to NULL (legacy rules unaffected).
|
|
35
|
+
ALTER TABLE alert_rules ADD COLUMN analysis_id TEXT;
|
|
36
|
+
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_alert_rules_analysis
|
|
38
|
+
ON alert_rules (project_id, analysis_id);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Seed a separate `obs-dashboard` project for the dashboard's own self-telemetry,
|
|
2
|
+
-- so dogfooded page_views / errors / interactions don't pollute the `default`
|
|
3
|
+
-- project that holds real demo + customer traffic.
|
|
4
|
+
INSERT OR IGNORE INTO projects (id, name, slug, created_at)
|
|
5
|
+
VALUES ('obs-dashboard', 'Obs Dashboard', 'obs-dashboard', datetime('now'));
|
|
6
|
+
|
|
7
|
+
-- Deterministic ingest key whose plaintext lives in apps/web/.env.development.local
|
|
8
|
+
-- (VITE_OBS_INGEST_KEY). Re-running this migration is a no-op via INSERT OR IGNORE
|
|
9
|
+
-- on the unique key_hash.
|
|
10
|
+
INSERT OR IGNORE INTO ingest_keys (id, project_id, key_hash, key_prefix, name, created_at)
|
|
11
|
+
VALUES (
|
|
12
|
+
'obs-dashboard-bootstrap',
|
|
13
|
+
'obs-dashboard',
|
|
14
|
+
'6aa18dc1261b312e98b236d5a7dae698d1a90ecbe33d8024744063a066a35b9b',
|
|
15
|
+
'obs_dashboard_65',
|
|
16
|
+
'bootstrap',
|
|
17
|
+
datetime('now')
|
|
18
|
+
);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
-- RFC 0004 — identity propagation.
|
|
2
|
+
--
|
|
3
|
+
-- Adds the `interaction_id` correlation key (a ULID minted by
|
|
4
|
+
-- @obs/analytics-sdk at click/submit/keydown time) to every signal that
|
|
5
|
+
-- carries it, plus the missing `session_id` column on `ai_calls`.
|
|
6
|
+
--
|
|
7
|
+
-- Why interaction_id: today, replay → trace navigation is approximate
|
|
8
|
+
-- (session_id + timestamp window). With a click-scoped correlation key we
|
|
9
|
+
-- can pivot from any rrweb event to the exact trace it caused, in either
|
|
10
|
+
-- direction.
|
|
11
|
+
--
|
|
12
|
+
-- metric_point intentionally does NOT get either column. Metrics aggregate;
|
|
13
|
+
-- tying a metric point to one click defeats the purpose. Exemplars
|
|
14
|
+
-- (already supported via metric_point.exemplars_json) are the correct
|
|
15
|
+
-- correlation primitive for metrics. Indexing exemplars for reverse lookup
|
|
16
|
+
-- is a follow-up flagged in the RFC.
|
|
17
|
+
|
|
18
|
+
ALTER TABLE telemetry_spans ADD COLUMN interaction_id TEXT;
|
|
19
|
+
ALTER TABLE logs ADD COLUMN interaction_id TEXT;
|
|
20
|
+
ALTER TABLE usage_events ADD COLUMN interaction_id TEXT;
|
|
21
|
+
ALTER TABLE ai_calls ADD COLUMN interaction_id TEXT;
|
|
22
|
+
ALTER TABLE ai_span_payloads ADD COLUMN interaction_id TEXT;
|
|
23
|
+
|
|
24
|
+
-- Backfill the one signal table missing session_id. ai_calls today
|
|
25
|
+
-- carries trace_id but no session, forcing a two-hop join through spans
|
|
26
|
+
-- to recover the user session that triggered an LLM call.
|
|
27
|
+
ALTER TABLE ai_calls ADD COLUMN session_id TEXT;
|
|
28
|
+
|
|
29
|
+
-- Partial indices keep the index small in the common case where most
|
|
30
|
+
-- rows predate this migration and therefore have NULL interaction_id.
|
|
31
|
+
-- SQLite/D1 supports partial indexes via the WHERE clause.
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_spans_interaction
|
|
33
|
+
ON telemetry_spans (project_id, interaction_id, received_at DESC)
|
|
34
|
+
WHERE interaction_id IS NOT NULL;
|
|
35
|
+
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_logs_interaction
|
|
37
|
+
ON logs (project_id, interaction_id, received_at DESC)
|
|
38
|
+
WHERE interaction_id IS NOT NULL;
|
|
39
|
+
|
|
40
|
+
CREATE INDEX IF NOT EXISTS idx_usage_interaction
|
|
41
|
+
ON usage_events (project_id, interaction_id, received_at DESC)
|
|
42
|
+
WHERE interaction_id IS NOT NULL;
|
|
43
|
+
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_ai_calls_interaction
|
|
45
|
+
ON ai_calls (project_id, interaction_id, received_at DESC)
|
|
46
|
+
WHERE interaction_id IS NOT NULL;
|
|
47
|
+
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_ai_calls_session
|
|
49
|
+
ON ai_calls (project_id, session_id, received_at DESC)
|
|
50
|
+
WHERE session_id IS NOT NULL;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
-- RFC 0007 — pprof profiling receiver storage.
|
|
2
|
+
--
|
|
3
|
+
-- Two tables:
|
|
4
|
+
-- profile_blobs — one row per ingested pprof blob (cpu / heap /
|
|
5
|
+
-- off-cpu / mutex / etc). The blob itself lives
|
|
6
|
+
-- in R2 (Workers) or filesystem (Node), keyed by
|
|
7
|
+
-- blob_url; this table is the metadata index.
|
|
8
|
+
-- profile_trace_index — one row per (profile, trace) pair so the
|
|
9
|
+
-- trace waterfall can join in O(1) on trace_id.
|
|
10
|
+
-- Populated at ingest from the
|
|
11
|
+
-- x-obs-trace-ids header (Phase 4 minimal) or
|
|
12
|
+
-- by parsing the pprof on later iterations.
|
|
13
|
+
--
|
|
14
|
+
-- The blob index uses an explicit join table rather than a JSON column
|
|
15
|
+
-- so a 60s profile from a high-traffic service touching thousands of
|
|
16
|
+
-- traces doesn't blow past D1's 2 MB row limit (see RFC 0007 §
|
|
17
|
+
-- profile_trace_index rationale).
|
|
18
|
+
|
|
19
|
+
CREATE TABLE IF NOT EXISTS profile_blobs (
|
|
20
|
+
id TEXT PRIMARY KEY, -- ULID minted at ingest
|
|
21
|
+
project_id TEXT NOT NULL,
|
|
22
|
+
service_name TEXT,
|
|
23
|
+
profile_type TEXT NOT NULL, -- 'cpu' | 'heap' | 'wall' | 'block' | 'mutex' | 'goroutine' | 'offcpu'
|
|
24
|
+
start_ts TEXT NOT NULL, -- ISO8601 — beginning of sampled window
|
|
25
|
+
end_ts TEXT NOT NULL,
|
|
26
|
+
duration_ms INTEGER NOT NULL,
|
|
27
|
+
blob_size_bytes INTEGER NOT NULL,
|
|
28
|
+
blob_url TEXT NOT NULL, -- R2 key or filesystem path
|
|
29
|
+
sample_count INTEGER, -- total samples (nullable — header-driven path doesn't know)
|
|
30
|
+
agent TEXT, -- 'datadog-pprof' | 'pyroscope' | 'parca-agent' | 'otel-ebpf' | unknown
|
|
31
|
+
resource_attrs_json TEXT, -- service.name, host.name, etc.
|
|
32
|
+
received_at TEXT NOT NULL,
|
|
33
|
+
expires_at TEXT NOT NULL
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_profile_blobs_service_ts
|
|
37
|
+
ON profile_blobs (project_id, service_name, end_ts DESC);
|
|
38
|
+
|
|
39
|
+
CREATE INDEX IF NOT EXISTS idx_profile_blobs_expires
|
|
40
|
+
ON profile_blobs (expires_at);
|
|
41
|
+
|
|
42
|
+
-- Trace→profile join. One row per (profile, trace) pair. ~50 bytes per row;
|
|
43
|
+
-- a profile sampling 5,000 distinct traces produces ~250 KB of join-table
|
|
44
|
+
-- rows, indexed for sub-ms lookup.
|
|
45
|
+
CREATE TABLE IF NOT EXISTS profile_trace_index (
|
|
46
|
+
profile_id TEXT NOT NULL,
|
|
47
|
+
trace_id TEXT NOT NULL,
|
|
48
|
+
project_id TEXT NOT NULL, -- denormalized for retention sweep
|
|
49
|
+
PRIMARY KEY (profile_id, trace_id),
|
|
50
|
+
FOREIGN KEY (profile_id) REFERENCES profile_blobs(id) ON DELETE CASCADE
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_profile_trace_index_trace
|
|
54
|
+
ON profile_trace_index (project_id, trace_id);
|
|
55
|
+
|
|
56
|
+
CREATE INDEX IF NOT EXISTS idx_profile_trace_index_profile
|
|
57
|
+
ON profile_trace_index (profile_id);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- RFC 0009 Phase 5.3 — denormalize telemetry.sdk.name onto telemetry_spans.
|
|
2
|
+
--
|
|
3
|
+
-- The service map dashboard wants a "show me only Beyla-derived edges"
|
|
4
|
+
-- filter. Doing that with json_extract on resource_attributes_json on
|
|
5
|
+
-- every aggregation row is too slow (no index possible on JSON paths
|
|
6
|
+
-- in D1). Denormalize at ingest into a top-level column with a partial
|
|
7
|
+
-- index — partial because most spans will continue to come from
|
|
8
|
+
-- regular SDKs and don't need the index entry.
|
|
9
|
+
--
|
|
10
|
+
-- Populated by default-span-enrichment from
|
|
11
|
+
-- resource_attributes['telemetry.sdk.name']. NULL when the producer
|
|
12
|
+
-- didn't set it (older SDKs); the service-map filter treats NULL as
|
|
13
|
+
-- "sdk-derived" (the conservative default) so existing edges keep
|
|
14
|
+
-- rendering when "sdk" is selected.
|
|
15
|
+
|
|
16
|
+
ALTER TABLE telemetry_spans ADD COLUMN telemetry_sdk_name TEXT;
|
|
17
|
+
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_spans_sdk_name
|
|
19
|
+
ON telemetry_spans (project_id, telemetry_sdk_name, received_at DESC)
|
|
20
|
+
WHERE telemetry_sdk_name IS NOT NULL;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- RFC 0002 Stage 4 follow-up — cron overlap protection.
|
|
2
|
+
--
|
|
3
|
+
-- Every-minute analyses tick + narrative-LLM latency could leave a single
|
|
4
|
+
-- analysis still running when the next tick fires. Without a claim, both
|
|
5
|
+
-- ticks pick up the same row (last_run_at hasn't moved yet on success-only
|
|
6
|
+
-- writes), and we double-spend on LLM calls and write duplicate result
|
|
7
|
+
-- rows.
|
|
8
|
+
--
|
|
9
|
+
-- last_started_at is the claim timestamp; the runner takes a 90-second
|
|
10
|
+
-- lease on the row before processing. A lease that's older than the
|
|
11
|
+
-- threshold is considered abandoned and the next tick may re-claim.
|
|
12
|
+
-- last_run_at continues to track completion time.
|
|
13
|
+
|
|
14
|
+
ALTER TABLE analysis_definitions ADD COLUMN last_started_at TEXT;
|
|
15
|
+
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_analysis_definitions_started
|
|
17
|
+
ON analysis_definitions (project_id, last_started_at)
|
|
18
|
+
WHERE last_started_at IS NOT NULL;
|