@wizeworks/lens-hub 0.0.0-stage → 0.3.0-alpha.2
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 -2
- package/dist/api.d.ts +20 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +90 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.d.ts +9 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +55 -0
- package/dist/auth.js.map +1 -0
- package/dist/body.d.ts +9 -0
- package/dist/body.d.ts.map +1 -0
- package/dist/body.js +25 -0
- package/dist/body.js.map +1 -0
- package/dist/cli-args.d.ts +10 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +63 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +35 -0
- package/dist/cli.js.map +1 -0
- package/dist/data.d.ts +17 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/data.js +39 -0
- package/dist/data.js.map +1 -0
- package/dist/hub.d.ts +14 -0
- package/dist/hub.d.ts.map +1 -0
- package/dist/hub.js +89 -0
- package/dist/hub.js.map +1 -0
- package/dist/import.d.ts +4 -0
- package/dist/import.d.ts.map +1 -0
- package/dist/import.js +41 -0
- package/dist/import.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest.d.ts +9 -0
- package/dist/ingest.d.ts.map +1 -0
- package/dist/ingest.js +83 -0
- package/dist/ingest.js.map +1 -0
- package/dist/kit.d.ts +10 -0
- package/dist/kit.d.ts.map +1 -0
- package/dist/kit.js +8 -0
- package/dist/kit.js.map +1 -0
- package/dist/mcp.d.ts +4 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +18 -0
- package/dist/mcp.js.map +1 -0
- package/dist/metrics-read.d.ts +12 -0
- package/dist/metrics-read.d.ts.map +1 -0
- package/dist/metrics-read.js +18 -0
- package/dist/metrics-read.js.map +1 -0
- package/dist/metrics-write.d.ts +12 -0
- package/dist/metrics-write.d.ts.map +1 -0
- package/dist/metrics-write.js +107 -0
- package/dist/metrics-write.js.map +1 -0
- package/dist/models-api.d.ts +5 -0
- package/dist/models-api.d.ts.map +1 -0
- package/dist/models-api.js +36 -0
- package/dist/models-api.js.map +1 -0
- package/dist/options.d.ts +36 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +22 -0
- package/dist/options.js.map +1 -0
- package/dist/otlp/index.d.ts +8 -0
- package/dist/otlp/index.d.ts.map +1 -0
- package/dist/otlp/index.js +41 -0
- package/dist/otlp/index.js.map +1 -0
- package/dist/otlp/logs.d.ts +24 -0
- package/dist/otlp/logs.d.ts.map +1 -0
- package/dist/otlp/logs.js +44 -0
- package/dist/otlp/logs.js.map +1 -0
- package/dist/otlp/metrics.d.ts +59 -0
- package/dist/otlp/metrics.d.ts.map +1 -0
- package/dist/otlp/metrics.js +73 -0
- package/dist/otlp/metrics.js.map +1 -0
- package/dist/otlp/proto.d.ts +14 -0
- package/dist/otlp/proto.d.ts.map +1 -0
- package/dist/otlp/proto.js +132 -0
- package/dist/otlp/proto.js.map +1 -0
- package/dist/otlp/spans.d.ts +33 -0
- package/dist/otlp/spans.d.ts.map +1 -0
- package/dist/otlp/spans.js +80 -0
- package/dist/otlp/spans.js.map +1 -0
- package/dist/otlp/values.d.ts +40 -0
- package/dist/otlp/values.d.ts.map +1 -0
- package/dist/otlp/values.js +78 -0
- package/dist/otlp/values.js.map +1 -0
- package/dist/scale-exec.d.ts +10 -0
- package/dist/scale-exec.d.ts.map +1 -0
- package/dist/scale-exec.js +22 -0
- package/dist/scale-exec.js.map +1 -0
- package/dist/schema-scale.d.ts +7 -0
- package/dist/schema-scale.d.ts.map +1 -0
- package/dist/schema-scale.js +99 -0
- package/dist/schema-scale.js.map +1 -0
- package/dist/schema.d.ts +13 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +49 -0
- package/dist/schema.js.map +1 -0
- package/dist/settle.d.ts +28 -0
- package/dist/settle.d.ts.map +1 -0
- package/dist/settle.js +103 -0
- package/dist/settle.js.map +1 -0
- package/dist/store-read.d.ts +27 -0
- package/dist/store-read.d.ts.map +1 -0
- package/dist/store-read.js +74 -0
- package/dist/store-read.js.map +1 -0
- package/dist/store.d.ts +42 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +118 -0
- package/dist/store.js.map +1 -0
- package/package.json +64 -3
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { isDbCall, redactAttributes } from "@wizeworks/lens-core";
|
|
2
|
+
import { attributesOf, hexId, nanosToMs, senderOf } from "./values.js";
|
|
3
|
+
const KINDS = ["internal", "internal", "server", "client", "producer", "consumer"];
|
|
4
|
+
const KIND_NAMES = {
|
|
5
|
+
SPAN_KIND_SERVER: "server",
|
|
6
|
+
SPAN_KIND_CLIENT: "client",
|
|
7
|
+
SPAN_KIND_PRODUCER: "producer",
|
|
8
|
+
SPAN_KIND_CONSUMER: "consumer",
|
|
9
|
+
};
|
|
10
|
+
const kindOf = (k) => (typeof k === "string" ? (KIND_NAMES[k] ?? "internal") : (KINDS[k ?? 0] ?? "internal"));
|
|
11
|
+
function statusOf(code) {
|
|
12
|
+
if (code === 2 || code === "STATUS_CODE_ERROR")
|
|
13
|
+
return "error";
|
|
14
|
+
if (code === 1 || code === "STATUS_CODE_OK")
|
|
15
|
+
return "ok";
|
|
16
|
+
return "unset";
|
|
17
|
+
}
|
|
18
|
+
/** The same rules the add-ons use (lens-node processor.ts). */
|
|
19
|
+
function categoryOf(kind, a) {
|
|
20
|
+
if (a["messaging.system"] != null)
|
|
21
|
+
return "messaging";
|
|
22
|
+
if (isDbCall(a))
|
|
23
|
+
return "db";
|
|
24
|
+
const web = a["http.request.method"] != null || a["rpc.system"] != null;
|
|
25
|
+
if (kind === "server" && web)
|
|
26
|
+
return "http.server";
|
|
27
|
+
if (kind === "client" && web)
|
|
28
|
+
return "http.client";
|
|
29
|
+
return "internal";
|
|
30
|
+
}
|
|
31
|
+
function clientName(a, fallback) {
|
|
32
|
+
try {
|
|
33
|
+
const u = new URL(String(a["url.full"]));
|
|
34
|
+
return `${String(a["http.request.method"] ?? "GET")} ${u.host}${u.pathname}`;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return fallback;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** One OTLP span as a contract span. Null when its ids are not valid. */
|
|
41
|
+
export function toSpan(s, service, redactKeys) {
|
|
42
|
+
const traceId = hexId(s.traceId, 32);
|
|
43
|
+
const spanId = hexId(s.spanId, 16);
|
|
44
|
+
if (!traceId || !spanId)
|
|
45
|
+
return null;
|
|
46
|
+
const kind = kindOf(s.kind);
|
|
47
|
+
const attributes = redactAttributes(attributesOf(s.attributes), redactKeys);
|
|
48
|
+
const category = categoryOf(kind, attributes);
|
|
49
|
+
const startMs = nanosToMs(s.startTimeUnixNano);
|
|
50
|
+
const name = String(s.name ?? "span").slice(0, 500);
|
|
51
|
+
return {
|
|
52
|
+
traceId,
|
|
53
|
+
spanId,
|
|
54
|
+
parentSpanId: hexId(s.parentSpanId, 16) ?? null,
|
|
55
|
+
name: category === "http.client" && attributes["url.full"] ? clientName(attributes, name) : name,
|
|
56
|
+
kind,
|
|
57
|
+
category,
|
|
58
|
+
service,
|
|
59
|
+
startMs,
|
|
60
|
+
durationMs: Math.max(0, nanosToMs(s.endTimeUnixNano) - startMs),
|
|
61
|
+
status: statusOf(s.status?.code),
|
|
62
|
+
statusMessage: s.status?.message || null,
|
|
63
|
+
attributes,
|
|
64
|
+
events: (s.events ?? []).slice(0, 50).map((e) => ({
|
|
65
|
+
name: String(e.name ?? "event"),
|
|
66
|
+
timeMs: nanosToMs(e.timeUnixNano),
|
|
67
|
+
attributes: redactAttributes(attributesOf(e.attributes), redactKeys),
|
|
68
|
+
})),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** One write per resource: each resource is one sender. */
|
|
72
|
+
export function writesFromSpans(list, redactKeys) {
|
|
73
|
+
return list.map((rs) => {
|
|
74
|
+
const sender = senderOf(rs.resource);
|
|
75
|
+
const spans = (rs.scopeSpans ?? []).flatMap((ss) => ss.spans ?? []);
|
|
76
|
+
const mapped = spans.map((s) => toSpan(s, sender.service, redactKeys)).filter((s) => s !== null);
|
|
77
|
+
return { sender, via: "otlp", spans: mapped, logs: [], remotes: [] };
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=spans.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spans.js","sourceRoot":"","sources":["../../src/otlp/spans.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AttributeValue, Attributes } from "@wizeworks/lens-core";
|
|
2
|
+
/** OTLP shapes after JSON parse or protobuf decode. Ids are hex, 64-bit numbers are strings or numbers. */
|
|
3
|
+
export interface OtlpAnyValue {
|
|
4
|
+
stringValue?: string;
|
|
5
|
+
boolValue?: boolean;
|
|
6
|
+
intValue?: string | number;
|
|
7
|
+
doubleValue?: number;
|
|
8
|
+
arrayValue?: {
|
|
9
|
+
values?: OtlpAnyValue[];
|
|
10
|
+
};
|
|
11
|
+
kvlistValue?: {
|
|
12
|
+
values?: OtlpKeyValue[];
|
|
13
|
+
};
|
|
14
|
+
bytesValue?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface OtlpKeyValue {
|
|
17
|
+
key: string;
|
|
18
|
+
value?: OtlpAnyValue;
|
|
19
|
+
}
|
|
20
|
+
export interface OtlpResource {
|
|
21
|
+
attributes?: OtlpKeyValue[];
|
|
22
|
+
}
|
|
23
|
+
/** One AnyValue as a contract attribute value. Arrays and maps become JSON text. */
|
|
24
|
+
export declare function valueOf(v: OtlpAnyValue | undefined): AttributeValue;
|
|
25
|
+
/** Key-value list as contract attributes, with older names copied to the current ones. */
|
|
26
|
+
export declare function attributesOf(list: OtlpKeyValue[] | undefined): Attributes;
|
|
27
|
+
/** Unix nanoseconds (string or number) as epoch ms. */
|
|
28
|
+
export declare function nanosToMs(v: string | number | undefined): number;
|
|
29
|
+
/** A 16- or 32-hex id, or undefined for an empty or all-zero id. */
|
|
30
|
+
export declare function hexId(v: string | undefined, length: 16 | 32): string | undefined;
|
|
31
|
+
/** The sender a resource describes. */
|
|
32
|
+
export declare function senderOf(resource: OtlpResource | undefined): {
|
|
33
|
+
service: string;
|
|
34
|
+
project: string | undefined;
|
|
35
|
+
version: string | undefined;
|
|
36
|
+
runtime: string;
|
|
37
|
+
environment: string | undefined;
|
|
38
|
+
host: string | undefined;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../src/otlp/values.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvE,2GAA2G;AAC3G,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;IACzC,WAAW,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;CAC7B;AAED,oFAAoF;AACpF,wBAAgB,OAAO,CAAC,CAAC,EAAE,YAAY,GAAG,SAAS,GAAG,cAAc,CAUnE;AAkBD,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,SAAS,GAAG,UAAU,CAOzE;AAED,uDAAuD;AACvD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAKhE;AAED,oEAAoE;AACpE,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,MAAM,GAAG,SAAS,CAIhF;AAED,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS;IAKvD,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,WAAW;IACX,IAAI;EAEP"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** One AnyValue as a contract attribute value. Arrays and maps become JSON text. */
|
|
2
|
+
export function valueOf(v) {
|
|
3
|
+
if (!v)
|
|
4
|
+
return null;
|
|
5
|
+
if (v.stringValue !== undefined)
|
|
6
|
+
return v.stringValue;
|
|
7
|
+
if (v.boolValue !== undefined)
|
|
8
|
+
return v.boolValue;
|
|
9
|
+
if (v.intValue !== undefined)
|
|
10
|
+
return Number(v.intValue);
|
|
11
|
+
if (v.doubleValue !== undefined)
|
|
12
|
+
return v.doubleValue;
|
|
13
|
+
if (v.arrayValue)
|
|
14
|
+
return JSON.stringify((v.arrayValue.values ?? []).map(valueOf));
|
|
15
|
+
if (v.kvlistValue)
|
|
16
|
+
return JSON.stringify(attributesOf(v.kvlistValue.values));
|
|
17
|
+
if (v.bytesValue !== undefined)
|
|
18
|
+
return v.bytesValue;
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
// Older semantic-convention names, mapped to the ones the dashboard reads.
|
|
22
|
+
const ALIASES = {
|
|
23
|
+
"http.method": "http.request.method",
|
|
24
|
+
"http.status_code": "http.response.status_code",
|
|
25
|
+
"http.url": "url.full",
|
|
26
|
+
"http.target": "url.path",
|
|
27
|
+
"http.scheme": "url.scheme",
|
|
28
|
+
"db.statement": "db.query.text",
|
|
29
|
+
"db.system": "db.system.name",
|
|
30
|
+
"db.name": "db.namespace",
|
|
31
|
+
"db.operation": "db.operation.name",
|
|
32
|
+
"net.peer.name": "server.address",
|
|
33
|
+
"net.peer.port": "server.port",
|
|
34
|
+
"deployment.environment": "deployment.environment.name",
|
|
35
|
+
};
|
|
36
|
+
/** Key-value list as contract attributes, with older names copied to the current ones. */
|
|
37
|
+
export function attributesOf(list) {
|
|
38
|
+
const out = {};
|
|
39
|
+
for (const kv of list ?? [])
|
|
40
|
+
if (kv?.key)
|
|
41
|
+
out[kv.key] = valueOf(kv.value);
|
|
42
|
+
for (const [old, current] of Object.entries(ALIASES)) {
|
|
43
|
+
if (out[old] !== undefined && out[current] === undefined)
|
|
44
|
+
out[current] = out[old];
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
/** Unix nanoseconds (string or number) as epoch ms. */
|
|
49
|
+
export function nanosToMs(v) {
|
|
50
|
+
if (v === undefined || v === "")
|
|
51
|
+
return 0;
|
|
52
|
+
if (typeof v === "number")
|
|
53
|
+
return v / 1e6;
|
|
54
|
+
const n = BigInt(v);
|
|
55
|
+
return Number(n / 1000n) / 1000;
|
|
56
|
+
}
|
|
57
|
+
/** A 16- or 32-hex id, or undefined for an empty or all-zero id. */
|
|
58
|
+
export function hexId(v, length) {
|
|
59
|
+
const id = v?.toLowerCase();
|
|
60
|
+
if (!id || id.length !== length || !/^[0-9a-f]+$/.test(id) || /^0+$/.test(id))
|
|
61
|
+
return undefined;
|
|
62
|
+
return id;
|
|
63
|
+
}
|
|
64
|
+
/** The sender a resource describes. */
|
|
65
|
+
export function senderOf(resource) {
|
|
66
|
+
const a = attributesOf(resource?.attributes);
|
|
67
|
+
const str = (k) => (typeof a[k] === "string" && a[k] ? String(a[k]).slice(0, 100) : undefined);
|
|
68
|
+
const lang = str("telemetry.sdk.language");
|
|
69
|
+
return {
|
|
70
|
+
service: str("service.name") ?? "unknown_service",
|
|
71
|
+
project: str("wizelens.project") ?? str("service.namespace"),
|
|
72
|
+
version: str("service.version"),
|
|
73
|
+
runtime: lang ? `otlp ${lang}` : "otlp",
|
|
74
|
+
environment: str("deployment.environment.name"),
|
|
75
|
+
host: str("host.name"),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=values.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.js","sourceRoot":"","sources":["../../src/otlp/values.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import { type Executor, type SqlRunner, type SqlScope } from "@wizeworks/lens-core";
|
|
3
|
+
import type { HubStore } from "./store.js";
|
|
4
|
+
/** Reads for the SQL executor, on the hub's file. */
|
|
5
|
+
export declare const sqliteRunner: (db: DatabaseSync) => SqlRunner;
|
|
6
|
+
/** Page needs from the hub's stats tables. Scope: an optional project and environment; the 1 h tier keeps `maxAgeMs`. */
|
|
7
|
+
export declare function hubExecutor(store: HubStore, scope?: SqlScope, keepRemote?: (endpoint: string) => boolean): Executor;
|
|
8
|
+
/** Traces in the scope still waiting for their stats, for `pageContext(..., settling)`. Null when none. */
|
|
9
|
+
export declare function hubSettling(store: HubStore, scope?: SqlScope): number | null;
|
|
10
|
+
//# sourceMappingURL=scale-exec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scale-exec.d.ts","sourceRoot":"","sources":["../src/scale-exec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,KAAK,QAAQ,EAAkB,KAAK,SAAS,EAAe,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEjH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,qDAAqD;AACrD,eAAO,MAAM,YAAY,OAAQ,YAAY,KAAG,SAE9C,CAAC;AAEH,yHAAyH;AACzH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,GAAE,QAAa,EAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,GAAG,QAAQ,CAQvH;AAED,2GAA2G;AAC3G,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,GAAE,QAAa,GAAG,MAAM,GAAG,IAAI,CAEhF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SQLITE_DIALECT, sqlExecutor } from "@wizeworks/lens-core";
|
|
2
|
+
import { settlingCount } from "./settle.js";
|
|
3
|
+
import { getStoredTrace } from "./store-read.js";
|
|
4
|
+
/** Reads for the SQL executor, on the hub's file. */
|
|
5
|
+
export const sqliteRunner = (db) => ({
|
|
6
|
+
all: async (sql, params) => db.prepare(sql).all(...params),
|
|
7
|
+
});
|
|
8
|
+
/** Page needs from the hub's stats tables. Scope: an optional project and environment; the 1 h tier keeps `maxAgeMs`. */
|
|
9
|
+
export function hubExecutor(store, scope = {}, keepRemote) {
|
|
10
|
+
return sqlExecutor({
|
|
11
|
+
d: SQLITE_DIALECT,
|
|
12
|
+
run: sqliteRunner(store.db),
|
|
13
|
+
scope,
|
|
14
|
+
retentionMs: store.maxAgeMs,
|
|
15
|
+
loadTrace: (id) => getStoredTrace(store.db, id, keepRemote) ?? null,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/** Traces in the scope still waiting for their stats, for `pageContext(..., settling)`. Null when none. */
|
|
19
|
+
export function hubSettling(store, scope = {}) {
|
|
20
|
+
return settlingCount(store.db, scope) || null;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=scale-exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scale-exec.js","sourceRoot":"","sources":["../src/scale-exec.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,cAAc,EAAkB,WAAW,EAAiB,MAAM,sBAAsB,CAAC;AACjH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,qDAAqD;AACrD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAAgB,EAAa,EAAE,CAAC,CAAC;IAC5D,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAI,MAA0B,CAA8B;CAC7G,CAAC,CAAC;AAEH,yHAAyH;AACzH,MAAM,UAAU,WAAW,CAAC,KAAe,EAAE,KAAK,GAAa,EAAE,EAAE,UAA0C;IAC3G,OAAO,WAAW,CAAC;QACjB,CAAC,EAAE,cAAc;QACjB,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,KAAK;QACL,WAAW,EAAE,KAAK,CAAC,QAAQ;QAC3B,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC,IAAI,IAAI;KACpE,CAAC,CAAC;AACL,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,WAAW,CAAC,KAAe,EAAE,KAAK,GAAa,EAAE;IAC/D,OAAO,aAAa,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
export declare const HUB_SCALE_SCHEMA: string;
|
|
3
|
+
/** Tables the stats rebuild clears. */
|
|
4
|
+
export declare const STATS_TABLES: string[];
|
|
5
|
+
/** Bring any hub file to the current schema. Older files gain the stats tables; the settle job then backfills them. */
|
|
6
|
+
export declare function upgradeHubSchema(db: DatabaseSync): void;
|
|
7
|
+
//# sourceMappingURL=schema-scale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-scale.d.ts","sourceRoot":"","sources":["../src/schema-scale.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA4BhD,eAAO,MAAM,gBAAgB,QAyC5B,CAAC;AAEF,uCAAuC;AACvC,eAAO,MAAM,YAAY,UAAwH,CAAC;AAkBlJ,uHAAuH;AACvH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CASvD"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { FACTS_VERSION } from "@wizeworks/lens-core";
|
|
2
|
+
import { HUB_SCHEMA, HUB_SCHEMA_VERSION } from "./schema.js";
|
|
3
|
+
// Stats tables (docs/CONTRACT.md, "Hub storage"): facts per trace, rollups per tier, and metric rollups. The tiers are identical.
|
|
4
|
+
const TIERS = ["10s", "5m", "1h"];
|
|
5
|
+
const rollupTable = (t) => `
|
|
6
|
+
CREATE TABLE IF NOT EXISTS rollup_${t} (
|
|
7
|
+
project TEXT NOT NULL DEFAULT '', env TEXT NOT NULL DEFAULT '', kind TEXT NOT NULL, key TEXT NOT NULL, bucket_ms REAL NOT NULL,
|
|
8
|
+
n REAL NOT NULL, err REAL NOT NULL, sum_v REAL NOT NULL, c0 REAL NOT NULL DEFAULT 0, c1 REAL NOT NULL DEFAULT 0, c2 REAL NOT NULL DEFAULT 0,
|
|
9
|
+
c3 REAL NOT NULL DEFAULT 0, c4 REAL NOT NULL DEFAULT 0, c5 REAL NOT NULL DEFAULT 0, first_ms REAL NOT NULL, last_ms REAL NOT NULL,
|
|
10
|
+
top_rank REAL NOT NULL DEFAULT 0, top TEXT, ids TEXT NOT NULL DEFAULT '', PRIMARY KEY (kind, bucket_ms, project, env, key)
|
|
11
|
+
);
|
|
12
|
+
CREATE INDEX IF NOT EXISTS ix_rollup_${t}_key ON rollup_${t} (kind, key, bucket_ms);
|
|
13
|
+
CREATE TABLE IF NOT EXISTS hist_${t} (
|
|
14
|
+
project TEXT NOT NULL DEFAULT '', env TEXT NOT NULL DEFAULT '', kind TEXT NOT NULL, key TEXT NOT NULL, bucket_ms REAL NOT NULL,
|
|
15
|
+
bin INTEGER NOT NULL, cnt REAL NOT NULL, PRIMARY KEY (kind, bucket_ms, project, env, key, bin)
|
|
16
|
+
);
|
|
17
|
+
CREATE TABLE IF NOT EXISTS metric_${t} (
|
|
18
|
+
project TEXT NOT NULL DEFAULT '', env TEXT NOT NULL DEFAULT '', series_key TEXT NOT NULL, name TEXT NOT NULL, bucket_ms REAL NOT NULL,
|
|
19
|
+
cnt REAL NOT NULL, vsum REAL NOT NULL, vmin REAL, vmax REAL, first_ms REAL NOT NULL, first_v REAL, last_ms REAL NOT NULL, last_v REAL,
|
|
20
|
+
rate_delta REAL NOT NULL DEFAULT 0, rate_ms REAL NOT NULL DEFAULT 0, h_count REAL NOT NULL DEFAULT 0, h_sum REAL NOT NULL DEFAULT 0,
|
|
21
|
+
h_min REAL, h_max REAL, h_bounds TEXT, h_counts TEXT, PRIMARY KEY (name, bucket_ms, project, env, series_key)
|
|
22
|
+
);
|
|
23
|
+
CREATE INDEX IF NOT EXISTS ix_metric_${t}_time ON metric_${t} (bucket_ms);`;
|
|
24
|
+
// Hub trace ids are unique, so fact keys start with the trace id; project is a column the scope filters on.
|
|
25
|
+
export const HUB_SCALE_SCHEMA = `
|
|
26
|
+
CREATE INDEX IF NOT EXISTS ix_traces_dirty ON traces(start_ms) WHERE settled_ms < updated_ms;
|
|
27
|
+
CREATE TABLE IF NOT EXISTS fact_requests (
|
|
28
|
+
project TEXT NOT NULL DEFAULT '', trace_id TEXT NOT NULL, env TEXT NOT NULL DEFAULT '', start_ms REAL NOT NULL,
|
|
29
|
+
method TEXT NOT NULL, path TEXT NOT NULL, endpoint TEXT NOT NULL, status INTEGER, status_class TEXT NOT NULL, failed INTEGER NOT NULL,
|
|
30
|
+
dur_class TEXT NOT NULL, aborted INTEGER NOT NULL, duration_ms REAL NOT NULL, server_ms REAL,
|
|
31
|
+
db_ms REAL NOT NULL, db_count INTEGER NOT NULL, fetch_count INTEGER NOT NULL, fetch_ms REAL NOT NULL,
|
|
32
|
+
render_ms REAL, network_ms REAL, service TEXT NOT NULL, services TEXT NOT NULL, errors INTEGER NOT NULL,
|
|
33
|
+
insights INTEGER NOT NULL, health TEXT NOT NULL, user_agent TEXT, client_address TEXT, end_user TEXT, request_id TEXT,
|
|
34
|
+
tags TEXT NOT NULL, search TEXT NOT NULL, PRIMARY KEY (trace_id)
|
|
35
|
+
);
|
|
36
|
+
CREATE INDEX IF NOT EXISTS ix_fact_requests_time ON fact_requests (start_ms);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS ix_fact_requests_project ON fact_requests (project, start_ms);
|
|
38
|
+
CREATE TABLE IF NOT EXISTS fact_traces (
|
|
39
|
+
project TEXT NOT NULL DEFAULT '', trace_id TEXT NOT NULL, env TEXT NOT NULL DEFAULT '', start_ms REAL NOT NULL, path TEXT NOT NULL,
|
|
40
|
+
duration_ms REAL NOT NULL, health TEXT, status TEXT NOT NULL, services TEXT NOT NULL, span_count INTEGER NOT NULL,
|
|
41
|
+
slow INTEGER NOT NULL, search TEXT NOT NULL, PRIMARY KEY (trace_id)
|
|
42
|
+
);
|
|
43
|
+
CREATE INDEX IF NOT EXISTS ix_fact_traces_time ON fact_traces (start_ms);
|
|
44
|
+
CREATE INDEX IF NOT EXISTS ix_fact_traces_project ON fact_traces (project, start_ms);
|
|
45
|
+
CREATE TABLE IF NOT EXISTS fact_logs (
|
|
46
|
+
project TEXT NOT NULL DEFAULT '', trace_id TEXT NOT NULL, idx INTEGER NOT NULL, env TEXT NOT NULL DEFAULT '', time_ms REAL NOT NULL,
|
|
47
|
+
level TEXT NOT NULL, level_rank INTEGER NOT NULL, service TEXT NOT NULL, category TEXT NOT NULL, message TEXT NOT NULL,
|
|
48
|
+
trace_name TEXT NOT NULL, span_id TEXT, attributes TEXT NOT NULL, search TEXT NOT NULL, PRIMARY KEY (trace_id, idx)
|
|
49
|
+
);
|
|
50
|
+
CREATE INDEX IF NOT EXISTS ix_fact_logs_time ON fact_logs (time_ms);
|
|
51
|
+
CREATE INDEX IF NOT EXISTS ix_fact_logs_project ON fact_logs (project, time_ms);
|
|
52
|
+
CREATE TABLE IF NOT EXISTS fact_critical (
|
|
53
|
+
project TEXT NOT NULL DEFAULT '', trace_id TEXT NOT NULL, span_id TEXT NOT NULL, env TEXT NOT NULL DEFAULT '', start_ms REAL NOT NULL,
|
|
54
|
+
duration_ms REAL NOT NULL, name TEXT NOT NULL, service TEXT NOT NULL, layer TEXT NOT NULL, PRIMARY KEY (trace_id, span_id)
|
|
55
|
+
);
|
|
56
|
+
CREATE INDEX IF NOT EXISTS ix_fact_critical_time ON fact_critical (start_ms);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS ix_fact_critical_project ON fact_critical (project, start_ms);
|
|
58
|
+
CREATE TABLE IF NOT EXISTS metric_series (
|
|
59
|
+
project TEXT NOT NULL DEFAULT '', env TEXT NOT NULL DEFAULT '', series_key TEXT NOT NULL, name TEXT NOT NULL, service TEXT NOT NULL,
|
|
60
|
+
kind TEXT NOT NULL, unit TEXT NOT NULL, description TEXT NOT NULL, monotonic INTEGER NOT NULL, temporality TEXT NOT NULL,
|
|
61
|
+
attributes TEXT NOT NULL, last_ms REAL NOT NULL, last_value REAL, last_hist TEXT, PRIMARY KEY (project, env, series_key)
|
|
62
|
+
);
|
|
63
|
+
CREATE INDEX IF NOT EXISTS ix_metric_series_name ON metric_series (name);
|
|
64
|
+
CREATE INDEX IF NOT EXISTS ix_metric_series_project ON metric_series (project, name);
|
|
65
|
+
${TIERS.map(rollupTable).join("\n")}
|
|
66
|
+
`;
|
|
67
|
+
/** Tables the stats rebuild clears. */
|
|
68
|
+
export const STATS_TABLES = ["fact_requests", "fact_traces", "fact_logs", "fact_critical", ...TIERS.flatMap((t) => [`rollup_${t}`, `hist_${t}`])];
|
|
69
|
+
const setMeta = (db, key, value) => db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run(key, value);
|
|
70
|
+
/** Clear facts and rollups and mark every trace unsettled, so the settle job rebuilds them. */
|
|
71
|
+
function rebuildStats(db) {
|
|
72
|
+
db.exec("BEGIN");
|
|
73
|
+
try {
|
|
74
|
+
for (const t of STATS_TABLES)
|
|
75
|
+
db.exec(`DELETE FROM ${t}`);
|
|
76
|
+
db.exec("UPDATE traces SET settled_ms = 0, contrib = NULL");
|
|
77
|
+
setMeta(db, "facts", String(FACTS_VERSION));
|
|
78
|
+
db.exec("COMMIT");
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
db.exec("ROLLBACK");
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Bring any hub file to the current schema. Older files gain the stats tables; the settle job then backfills them. */
|
|
86
|
+
export function upgradeHubSchema(db) {
|
|
87
|
+
db.exec(HUB_SCHEMA);
|
|
88
|
+
const cols = new Set(db.prepare("PRAGMA table_info(traces)").all().map((c) => c.name));
|
|
89
|
+
if (!cols.has("settled_ms"))
|
|
90
|
+
db.exec("ALTER TABLE traces ADD COLUMN settled_ms REAL NOT NULL DEFAULT 0");
|
|
91
|
+
if (!cols.has("contrib"))
|
|
92
|
+
db.exec("ALTER TABLE traces ADD COLUMN contrib TEXT");
|
|
93
|
+
db.exec(HUB_SCALE_SCHEMA);
|
|
94
|
+
const facts = db.prepare("SELECT value FROM meta WHERE key = 'facts'").get();
|
|
95
|
+
if (facts?.value !== String(FACTS_VERSION))
|
|
96
|
+
rebuildStats(db);
|
|
97
|
+
setMeta(db, "schema", HUB_SCHEMA_VERSION);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=schema-scale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-scale.js","sourceRoot":"","sources":["../src/schema-scale.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE7D,kIAAkI;AAClI,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAElC,MAAM,WAAW,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC;oCACC,CAAC;;;;;;uCAME,CAAC,kBAAkB,CAAC;kCACzB,CAAC;;;;oCAIC,CAAC;;;;;;uCAME,CAAC,mBAAmB,CAAC,eAAe,CAAC;AAE5E,4GAA4G;AAC5G,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwC9B,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;CAClC,CAAC;AAEF,uCAAuC;AACvC,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAElJ,MAAM,OAAO,GAAG,CAAC,EAAgB,EAAE,GAAW,EAAE,KAAa,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,wDAAwD,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAEvJ,+FAA+F;AAC/F,SAAS,YAAY,CAAC,EAAgB;IACpC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjB,IAAI,CAAC;QACH,KAAK,MAAM,CAAC,IAAI,YAAY;YAAE,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAC1D,EAAE,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;QAC5D,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;QAC5C,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpB,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,uHAAuH;AACvH,MAAM,UAAU,gBAAgB,CAAC,EAAgB;IAC/C,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACpB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAE,EAAE,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,GAAG,EAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/G,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC;QAAE,EAAE,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;IACzG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,EAAE,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IAChF,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC,GAAG,EAAmC,CAAC;IAC9G,IAAI,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,aAAa,CAAC;QAAE,YAAY,CAAC,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC;AAC5C,CAAC"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DatabaseSync, StatementSync } from "node:sqlite";
|
|
2
|
+
export declare const HUB_SCHEMA_VERSION = "3";
|
|
3
|
+
export declare const HUB_SCHEMA = "\nCREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);\nCREATE TABLE IF NOT EXISTS traces (\n trace_id TEXT PRIMARY KEY, start_ms REAL NOT NULL, end_ms REAL NOT NULL, updated_ms REAL NOT NULL,\n env TEXT NOT NULL DEFAULT '', project TEXT NOT NULL DEFAULT ''\n);\nCREATE TABLE IF NOT EXISTS spans (\n trace_id TEXT NOT NULL, span_id TEXT NOT NULL, service TEXT NOT NULL, start_ms REAL NOT NULL,\n duration_ms REAL NOT NULL, session TEXT, json TEXT NOT NULL, PRIMARY KEY (trace_id, span_id)\n);\nCREATE TABLE IF NOT EXISTS logs (\n trace_id TEXT NOT NULL, key TEXT NOT NULL, time_ms REAL NOT NULL, json TEXT NOT NULL, PRIMARY KEY (trace_id, key)\n);\nCREATE TABLE IF NOT EXISTS remotes (trace_id TEXT NOT NULL, endpoint TEXT NOT NULL, PRIMARY KEY (trace_id, endpoint));\nCREATE TABLE IF NOT EXISTS services (\n project TEXT NOT NULL, service TEXT NOT NULL, environment TEXT NOT NULL, host TEXT NOT NULL, via TEXT NOT NULL, info TEXT NOT NULL,\n first_seen REAL NOT NULL, last_seen REAL NOT NULL, PRIMARY KEY (project, service, environment, host)\n);\nCREATE TABLE IF NOT EXISTS metrics (\n time_ms REAL NOT NULL, project TEXT NOT NULL DEFAULT '', env TEXT NOT NULL DEFAULT '', service TEXT NOT NULL,\n name TEXT NOT NULL, series_key TEXT NOT NULL, json TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS ix_metrics_time ON metrics(time_ms);\nCREATE INDEX IF NOT EXISTS ix_metrics_name ON metrics(name, time_ms);\nCREATE INDEX IF NOT EXISTS ix_metrics_project ON metrics(project, time_ms);\nCREATE INDEX IF NOT EXISTS ix_traces_updated ON traces(updated_ms);\nCREATE INDEX IF NOT EXISTS ix_traces_start ON traces(start_ms);\nCREATE INDEX IF NOT EXISTS ix_traces_env ON traces(env, start_ms);\nCREATE INDEX IF NOT EXISTS ix_traces_project ON traces(project, start_ms);\nCREATE INDEX IF NOT EXISTS ix_spans_session ON spans(session) WHERE session IS NOT NULL;\n";
|
|
4
|
+
export interface HubStatements {
|
|
5
|
+
upsertTrace: StatementSync;
|
|
6
|
+
upsertSpan: StatementSync;
|
|
7
|
+
insertLog: StatementSync;
|
|
8
|
+
insertRemote: StatementSync;
|
|
9
|
+
upsertService: StatementSync;
|
|
10
|
+
insertMetric: StatementSync;
|
|
11
|
+
}
|
|
12
|
+
export declare function prepareHubStatements(db: DatabaseSync): HubStatements;
|
|
13
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG/D,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,UAAU,i2DA8BtB,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,aAAa,CAAC;IAC3B,UAAU,EAAE,aAAa,CAAC;IAC1B,SAAS,EAAE,aAAa,CAAC;IACzB,YAAY,EAAE,aAAa,CAAC;IAC5B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,aAAa,CAAC;CAC7B;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,GAAG,aAAa,CAcpE"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// The hub file (docs/CONTRACT.md, "Hub storage"). Empty strings stand for "unknown" so keys stay unique.
|
|
2
|
+
export const HUB_SCHEMA_VERSION = "3";
|
|
3
|
+
export const HUB_SCHEMA = `
|
|
4
|
+
CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
|
|
5
|
+
CREATE TABLE IF NOT EXISTS traces (
|
|
6
|
+
trace_id TEXT PRIMARY KEY, start_ms REAL NOT NULL, end_ms REAL NOT NULL, updated_ms REAL NOT NULL,
|
|
7
|
+
env TEXT NOT NULL DEFAULT '', project TEXT NOT NULL DEFAULT ''
|
|
8
|
+
);
|
|
9
|
+
CREATE TABLE IF NOT EXISTS spans (
|
|
10
|
+
trace_id TEXT NOT NULL, span_id TEXT NOT NULL, service TEXT NOT NULL, start_ms REAL NOT NULL,
|
|
11
|
+
duration_ms REAL NOT NULL, session TEXT, json TEXT NOT NULL, PRIMARY KEY (trace_id, span_id)
|
|
12
|
+
);
|
|
13
|
+
CREATE TABLE IF NOT EXISTS logs (
|
|
14
|
+
trace_id TEXT NOT NULL, key TEXT NOT NULL, time_ms REAL NOT NULL, json TEXT NOT NULL, PRIMARY KEY (trace_id, key)
|
|
15
|
+
);
|
|
16
|
+
CREATE TABLE IF NOT EXISTS remotes (trace_id TEXT NOT NULL, endpoint TEXT NOT NULL, PRIMARY KEY (trace_id, endpoint));
|
|
17
|
+
CREATE TABLE IF NOT EXISTS services (
|
|
18
|
+
project TEXT NOT NULL, service TEXT NOT NULL, environment TEXT NOT NULL, host TEXT NOT NULL, via TEXT NOT NULL, info TEXT NOT NULL,
|
|
19
|
+
first_seen REAL NOT NULL, last_seen REAL NOT NULL, PRIMARY KEY (project, service, environment, host)
|
|
20
|
+
);
|
|
21
|
+
CREATE TABLE IF NOT EXISTS metrics (
|
|
22
|
+
time_ms REAL NOT NULL, project TEXT NOT NULL DEFAULT '', env TEXT NOT NULL DEFAULT '', service TEXT NOT NULL,
|
|
23
|
+
name TEXT NOT NULL, series_key TEXT NOT NULL, json TEXT NOT NULL
|
|
24
|
+
);
|
|
25
|
+
CREATE INDEX IF NOT EXISTS ix_metrics_time ON metrics(time_ms);
|
|
26
|
+
CREATE INDEX IF NOT EXISTS ix_metrics_name ON metrics(name, time_ms);
|
|
27
|
+
CREATE INDEX IF NOT EXISTS ix_metrics_project ON metrics(project, time_ms);
|
|
28
|
+
CREATE INDEX IF NOT EXISTS ix_traces_updated ON traces(updated_ms);
|
|
29
|
+
CREATE INDEX IF NOT EXISTS ix_traces_start ON traces(start_ms);
|
|
30
|
+
CREATE INDEX IF NOT EXISTS ix_traces_env ON traces(env, start_ms);
|
|
31
|
+
CREATE INDEX IF NOT EXISTS ix_traces_project ON traces(project, start_ms);
|
|
32
|
+
CREATE INDEX IF NOT EXISTS ix_spans_session ON spans(session) WHERE session IS NOT NULL;
|
|
33
|
+
`;
|
|
34
|
+
export function prepareHubStatements(db) {
|
|
35
|
+
return {
|
|
36
|
+
upsertTrace: db.prepare(`INSERT INTO traces (trace_id, start_ms, end_ms, updated_ms, env, project) VALUES (?, ?, ?, ?, ?, ?)
|
|
37
|
+
ON CONFLICT(trace_id) DO UPDATE SET start_ms = min(start_ms, excluded.start_ms), end_ms = max(end_ms, excluded.end_ms),
|
|
38
|
+
updated_ms = excluded.updated_ms, env = CASE WHEN env = '' THEN excluded.env ELSE env END,
|
|
39
|
+
project = CASE WHEN project = '' THEN excluded.project ELSE project END`),
|
|
40
|
+
upsertSpan: db.prepare(`INSERT OR REPLACE INTO spans (trace_id, span_id, service, start_ms, duration_ms, session, json)
|
|
41
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`),
|
|
42
|
+
insertLog: db.prepare("INSERT OR IGNORE INTO logs (trace_id, key, time_ms, json) VALUES (?, ?, ?, ?)"),
|
|
43
|
+
insertRemote: db.prepare("INSERT OR IGNORE INTO remotes (trace_id, endpoint) VALUES (?, ?)"),
|
|
44
|
+
insertMetric: db.prepare("INSERT INTO metrics (time_ms, project, env, service, name, series_key, json) VALUES (?, ?, ?, ?, ?, ?, ?)"),
|
|
45
|
+
upsertService: db.prepare(`INSERT INTO services (project, service, environment, host, via, info, first_seen, last_seen)
|
|
46
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(project, service, environment, host) DO UPDATE SET via = excluded.via, info = excluded.info, last_seen = excluded.last_seen`),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAEA,yGAAyG;AACzG,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BzB,CAAC;AAWF,MAAM,UAAU,oBAAoB,CAAC,EAAgB;IACnD,OAAO;QACL,WAAW,EAAE,EAAE,CAAC,OAAO,CAAC;;;gFAGoD,CAAC;QAC7E,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC;mCACQ,CAAC;QAChC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,+EAA+E,CAAC;QACtG,YAAY,EAAE,EAAE,CAAC,OAAO,CAAC,kEAAkE,CAAC;QAC5F,YAAY,EAAE,EAAE,CAAC,OAAO,CAAC,2GAA2G,CAAC;QACrI,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC;8KACgJ,CAAC;KAC5K,CAAC;AACJ,CAAC"}
|
package/dist/settle.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import { type Statement } from "@wizeworks/lens-core";
|
|
3
|
+
import type { HubStore } from "./store.js";
|
|
4
|
+
/** A trace row as the settle and prune steps read it. */
|
|
5
|
+
export interface TraceStateRow {
|
|
6
|
+
trace_id: string;
|
|
7
|
+
project: string;
|
|
8
|
+
env: string;
|
|
9
|
+
updated_ms?: number;
|
|
10
|
+
contrib: string | null;
|
|
11
|
+
}
|
|
12
|
+
/** Run statements in the caller's transaction, with prepared statements kept per file. */
|
|
13
|
+
export declare function runStatements(db: DatabaseSync, statements: readonly Statement[]): void;
|
|
14
|
+
/** Settle dirty traces for up to `budgetMs`, so the event loop is not held for long. Returns how many settled. */
|
|
15
|
+
export declare function settleHub(store: HubStore, o?: {
|
|
16
|
+
budgetMs?: number;
|
|
17
|
+
batch?: number;
|
|
18
|
+
}): number;
|
|
19
|
+
/** The settle timer's job: errors are logged, never thrown into the timer. */
|
|
20
|
+
export declare function settleQuietly(store: HubStore): void;
|
|
21
|
+
/** In the prune transaction: take the doomed traces out of the rollups, drop their facts, and age out rollup buckets. */
|
|
22
|
+
export declare function pruneStats(store: HubStore, doomed: readonly TraceStateRow[]): void;
|
|
23
|
+
/** Traces whose stats are not built yet, for "Preparing stats". */
|
|
24
|
+
export declare function settlingCount(db: DatabaseSync, scope?: {
|
|
25
|
+
project?: string;
|
|
26
|
+
env?: string;
|
|
27
|
+
}): number;
|
|
28
|
+
//# sourceMappingURL=settle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settle.d.ts","sourceRoot":"","sources":["../src/settle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAgC,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAqD,KAAK,SAAS,EAAgE,MAAM,sBAAsB,CAAC;AAEvK,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS3C,yDAAyD;AACzD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAID,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,EAAE,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,IAAI,CAWtF;AAsCD,kHAAkH;AAClH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CAWhG;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAMnD;AAED,yHAAyH;AACzH,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI,CAOlF;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CAMtG"}
|
package/dist/settle.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { pruneStatements, SQLITE_DIALECT, settleStatements, tierByName, tierCutoff, tierPruneStatements } from "@wizeworks/lens-core";
|
|
2
|
+
import { loadTraces } from "./store-read.js";
|
|
3
|
+
// Settling: traces quiet for a while get their facts and rollups rebuilt from the stored spans and logs (docs/CONTRACT.md).
|
|
4
|
+
const BATCH = 200;
|
|
5
|
+
const BUDGET_MS = 150;
|
|
6
|
+
const QUIET_MS = 5_000;
|
|
7
|
+
const BUSY_MS = 30_000;
|
|
8
|
+
const CACHE_MAX = 300;
|
|
9
|
+
const caches = new WeakMap();
|
|
10
|
+
/** Run statements in the caller's transaction, with prepared statements kept per file. */
|
|
11
|
+
export function runStatements(db, statements) {
|
|
12
|
+
let cache = caches.get(db);
|
|
13
|
+
if (!cache)
|
|
14
|
+
caches.set(db, (cache = new Map()));
|
|
15
|
+
for (const s of statements) {
|
|
16
|
+
let st = cache.get(s.sql);
|
|
17
|
+
if (!st) {
|
|
18
|
+
if (cache.size >= CACHE_MAX)
|
|
19
|
+
cache.clear();
|
|
20
|
+
cache.set(s.sql, (st = db.prepare(s.sql)));
|
|
21
|
+
}
|
|
22
|
+
st.run(...s.params);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function inTransaction(db, fn) {
|
|
26
|
+
db.exec("BEGIN");
|
|
27
|
+
try {
|
|
28
|
+
fn();
|
|
29
|
+
db.exec("COMMIT");
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
db.exec("ROLLBACK");
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const stateOf = (store, r) => ({
|
|
37
|
+
traceId: r.trace_id,
|
|
38
|
+
project: r.project,
|
|
39
|
+
env: r.env,
|
|
40
|
+
updatedMs: r.updated_ms ?? 0,
|
|
41
|
+
contrib: r.contrib,
|
|
42
|
+
retentionMs: store.maxAgeMs,
|
|
43
|
+
});
|
|
44
|
+
/** Settle one batch of dirty traces, newest first. Returns how many. */
|
|
45
|
+
function settleBatch(store, batch) {
|
|
46
|
+
const now = store.now();
|
|
47
|
+
const rows = store.db
|
|
48
|
+
.prepare(`SELECT trace_id, project, env, updated_ms, contrib FROM traces WHERE settled_ms < updated_ms AND (updated_ms <= ? OR settled_ms <= ?)
|
|
49
|
+
ORDER BY start_ms DESC LIMIT ?`)
|
|
50
|
+
.all(now - QUIET_MS, now - BUSY_MS, batch);
|
|
51
|
+
if (!rows.length)
|
|
52
|
+
return 0;
|
|
53
|
+
const traces = loadTraces(store.db, rows.map((r) => r.trace_id));
|
|
54
|
+
const work = rows.map((r, i) => ({ state: stateOf(store, r), trace: traces[i] }));
|
|
55
|
+
inTransaction(store.db, () => runStatements(store.db, settleStatements(SQLITE_DIALECT, work, now, false)));
|
|
56
|
+
return rows.length;
|
|
57
|
+
}
|
|
58
|
+
/** Settle dirty traces for up to `budgetMs`, so the event loop is not held for long. Returns how many settled. */
|
|
59
|
+
export function settleHub(store, o = {}) {
|
|
60
|
+
const start = performance.now();
|
|
61
|
+
const batch = o.batch ?? BATCH;
|
|
62
|
+
let total = 0;
|
|
63
|
+
for (;;) {
|
|
64
|
+
const n = settleBatch(store, batch);
|
|
65
|
+
total += n;
|
|
66
|
+
if (n < batch || performance.now() - start >= (o.budgetMs ?? BUDGET_MS))
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
if (total)
|
|
70
|
+
store.settleGen++;
|
|
71
|
+
return total;
|
|
72
|
+
}
|
|
73
|
+
/** The settle timer's job: errors are logged, never thrown into the timer. */
|
|
74
|
+
export function settleQuietly(store) {
|
|
75
|
+
try {
|
|
76
|
+
settleHub(store);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
console.error("[wizelens-hub] settle failed:", err);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** In the prune transaction: take the doomed traces out of the rollups, drop their facts, and age out rollup buckets. */
|
|
83
|
+
export function pruneStats(store, doomed) {
|
|
84
|
+
const now = store.now();
|
|
85
|
+
runStatements(store.db, pruneStatements(SQLITE_DIALECT, doomed.map((r) => stateOf(store, r)), now, false));
|
|
86
|
+
runStatements(store.db, tierPruneStatements(now, true));
|
|
87
|
+
const cutoff = tierCutoff(tierByName("1h"), now, store.maxAgeMs);
|
|
88
|
+
for (const t of ["rollup_1h", "hist_1h"])
|
|
89
|
+
store.db.prepare(`DELETE FROM ${t} WHERE bucket_ms <= ?`).run(cutoff);
|
|
90
|
+
if (doomed.length)
|
|
91
|
+
store.settleGen++;
|
|
92
|
+
}
|
|
93
|
+
/** Traces whose stats are not built yet, for "Preparing stats". */
|
|
94
|
+
export function settlingCount(db, scope = {}) {
|
|
95
|
+
const where = ["settled_ms < updated_ms"];
|
|
96
|
+
const args = [];
|
|
97
|
+
if (scope.project)
|
|
98
|
+
where.push("project = ?"), args.push(scope.project);
|
|
99
|
+
if (scope.env)
|
|
100
|
+
where.push("env = ?"), args.push(scope.env);
|
|
101
|
+
return db.prepare(`SELECT count(*) AS n FROM traces WHERE ${where.join(" AND ")}`).get(...args).n;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=settle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settle.js","sourceRoot":"","sources":["../src/settle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import { type HubService, type Trace } from "@wizeworks/lens-core";
|
|
3
|
+
export interface TraceQuery {
|
|
4
|
+
/** Only traces that changed at or after this time (epoch ms, hub clock). */
|
|
5
|
+
since?: number;
|
|
6
|
+
/** Only traces that started before this time. For paging back. */
|
|
7
|
+
before?: number;
|
|
8
|
+
env?: string;
|
|
9
|
+
project?: string;
|
|
10
|
+
/** Only traces with a browser span from this tab. */
|
|
11
|
+
session?: string;
|
|
12
|
+
limit: number;
|
|
13
|
+
}
|
|
14
|
+
/** Trace ids that match, newest first. */
|
|
15
|
+
export declare function findTraceIds(db: DatabaseSync, q: TraceQuery): string[];
|
|
16
|
+
/** Build full traces, in the order of `ids`. `keepRemote` drops remotes the hub already has. */
|
|
17
|
+
export declare function loadTraces(db: DatabaseSync, ids: readonly string[], keepRemote?: (endpoint: string) => boolean): Trace[];
|
|
18
|
+
export declare function getStoredTrace(db: DatabaseSync, traceId: string, keepRemote?: (endpoint: string) => boolean): Trace | undefined;
|
|
19
|
+
/** Every service the hub knows, online ones first. */
|
|
20
|
+
export declare function listServices(db: DatabaseSync, now: number): HubService[];
|
|
21
|
+
/** Environments (or projects) seen in services and traces, sorted. */
|
|
22
|
+
export declare function distinctOf(db: DatabaseSync, field: "env" | "project"): string[];
|
|
23
|
+
export declare function countRows(db: DatabaseSync): {
|
|
24
|
+
traces: number;
|
|
25
|
+
spans: number;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=store-read.d.ts.map
|