@superblocksteam/sdk 2.0.130-next.3 → 2.0.130-next.4
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/.turbo/turbo-build.log +1 -1
- package/dist/cli-replacement/dependency-install-classifier.d.mts.map +1 -1
- package/dist/cli-replacement/dependency-install-classifier.mjs +11 -0
- package/dist/cli-replacement/dependency-install-classifier.mjs.map +1 -1
- package/dist/cli-replacement/dependency-install-classifier.test.mjs +26 -0
- package/dist/cli-replacement/dependency-install-classifier.test.mjs.map +1 -1
- package/dist/cli-replacement/dev.d.mts.map +1 -1
- package/dist/cli-replacement/dev.mjs +63 -4
- package/dist/cli-replacement/dev.mjs.map +1 -1
- package/dist/cli-replacement/disk-space.d.mts +86 -0
- package/dist/cli-replacement/disk-space.d.mts.map +1 -0
- package/dist/cli-replacement/disk-space.mjs +133 -0
- package/dist/cli-replacement/disk-space.mjs.map +1 -0
- package/dist/cli-replacement/disk-space.test.d.mts +2 -0
- package/dist/cli-replacement/disk-space.test.d.mts.map +1 -0
- package/dist/cli-replacement/disk-space.test.mjs +186 -0
- package/dist/cli-replacement/disk-space.test.mjs.map +1 -0
- package/dist/dev-utils/dev-server-metrics.d.mts +11 -0
- package/dist/dev-utils/dev-server-metrics.d.mts.map +1 -1
- package/dist/dev-utils/dev-server-metrics.mjs +18 -0
- package/dist/dev-utils/dev-server-metrics.mjs.map +1 -1
- package/dist/telemetry/memory-metrics.d.ts +7 -0
- package/dist/telemetry/memory-metrics.d.ts.map +1 -1
- package/dist/telemetry/memory-metrics.js +221 -44
- package/dist/telemetry/memory-metrics.js.map +1 -1
- package/dist/telemetry/memory-metrics.test.d.ts +2 -0
- package/dist/telemetry/memory-metrics.test.d.ts.map +1 -0
- package/dist/telemetry/memory-metrics.test.js +256 -0
- package/dist/telemetry/memory-metrics.test.js.map +1 -0
- package/package.json +6 -6
- package/src/cli-replacement/dependency-install-classifier.mts +14 -0
- package/src/cli-replacement/dependency-install-classifier.test.mts +39 -0
- package/src/cli-replacement/dev.mts +81 -10
- package/src/cli-replacement/disk-space.mts +216 -0
- package/src/cli-replacement/disk-space.test.mts +246 -0
- package/src/dev-utils/dev-server-metrics.mts +20 -0
- package/src/telemetry/memory-metrics.test.ts +363 -0
- package/src/telemetry/memory-metrics.ts +329 -60
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import {
|
|
3
|
+
constants,
|
|
4
|
+
monitorEventLoopDelay,
|
|
5
|
+
performance,
|
|
2
6
|
PerformanceObserver,
|
|
3
7
|
type PerformanceObserverEntryList,
|
|
4
8
|
} from "node:perf_hooks";
|
|
9
|
+
import { getHeapStatistics } from "node:v8";
|
|
5
10
|
|
|
6
11
|
import type { BatchObservableResult } from "@opentelemetry/api";
|
|
7
12
|
|
|
@@ -9,77 +14,341 @@ import { getMeter } from "./index.js";
|
|
|
9
14
|
|
|
10
15
|
let cleanupFn: (() => void) | undefined;
|
|
11
16
|
|
|
17
|
+
interface CgroupMemory {
|
|
18
|
+
currentBytes: number;
|
|
19
|
+
limitBytes: number;
|
|
20
|
+
usageRatio: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface CgroupNumber {
|
|
24
|
+
exists: boolean;
|
|
25
|
+
value?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface GcPerformanceEntry {
|
|
29
|
+
duration: number;
|
|
30
|
+
kind?: number;
|
|
31
|
+
detail?: {
|
|
32
|
+
kind?: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const NS_PER_MS = 1_000_000;
|
|
37
|
+
const US_PER_SECOND = 1_000_000;
|
|
38
|
+
|
|
39
|
+
function finiteNonNegative(value: number): number {
|
|
40
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function nsToMs(value: number): number {
|
|
44
|
+
return finiteNonNegative(value) / NS_PER_MS;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function ratio(numerator: number, denominator: number): number {
|
|
48
|
+
if (!Number.isFinite(numerator) || !Number.isFinite(denominator)) {
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
if (denominator <= 0) {
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
return Math.max(0, numerator / denominator);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function readCgroupNumber(filePath: string): CgroupNumber {
|
|
58
|
+
try {
|
|
59
|
+
const value = readFileSync(filePath, "utf-8").trim();
|
|
60
|
+
if (!value || value === "max") {
|
|
61
|
+
return { exists: true };
|
|
62
|
+
}
|
|
63
|
+
const parsed = Number(value);
|
|
64
|
+
if (
|
|
65
|
+
Number.isFinite(parsed) &&
|
|
66
|
+
parsed >= 0 &&
|
|
67
|
+
parsed < Number.MAX_SAFE_INTEGER
|
|
68
|
+
) {
|
|
69
|
+
return { exists: true, value: parsed };
|
|
70
|
+
}
|
|
71
|
+
return { exists: true };
|
|
72
|
+
} catch {
|
|
73
|
+
return { exists: false };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function readCgroupMemory(
|
|
78
|
+
root = "/sys/fs/cgroup",
|
|
79
|
+
): CgroupMemory | undefined {
|
|
80
|
+
const v2Current = readCgroupNumber(`${root}/memory.current`);
|
|
81
|
+
const v2Limit = readCgroupNumber(`${root}/memory.max`);
|
|
82
|
+
const usesCgroupV2 = v2Current.exists || v2Limit.exists;
|
|
83
|
+
const currentBytes = usesCgroupV2
|
|
84
|
+
? v2Current.value
|
|
85
|
+
: readCgroupNumber(`${root}/memory/memory.usage_in_bytes`).value;
|
|
86
|
+
const limitBytes = usesCgroupV2
|
|
87
|
+
? v2Limit.value
|
|
88
|
+
: readCgroupNumber(`${root}/memory/memory.limit_in_bytes`).value;
|
|
89
|
+
|
|
90
|
+
if (
|
|
91
|
+
currentBytes === undefined ||
|
|
92
|
+
limitBytes === undefined ||
|
|
93
|
+
limitBytes <= 0
|
|
94
|
+
) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
currentBytes,
|
|
100
|
+
limitBytes,
|
|
101
|
+
usageRatio: ratio(currentBytes, limitBytes),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function gcKind(kind: number | undefined): string {
|
|
106
|
+
switch (kind) {
|
|
107
|
+
case constants.NODE_PERFORMANCE_GC_MINOR:
|
|
108
|
+
return "minor";
|
|
109
|
+
case constants.NODE_PERFORMANCE_GC_MAJOR:
|
|
110
|
+
return "major";
|
|
111
|
+
case constants.NODE_PERFORMANCE_GC_INCREMENTAL:
|
|
112
|
+
return "incremental";
|
|
113
|
+
case constants.NODE_PERFORMANCE_GC_WEAKCB:
|
|
114
|
+
return "weakcb";
|
|
115
|
+
default:
|
|
116
|
+
return "unknown";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
12
120
|
export function startMemoryMetrics(): void {
|
|
13
121
|
if (cleanupFn) {
|
|
14
122
|
return;
|
|
15
123
|
}
|
|
16
124
|
|
|
17
125
|
const meter = getMeter();
|
|
126
|
+
const eventLoopDelay = monitorEventLoopDelay({ resolution: 20 });
|
|
127
|
+
let previousEventLoopUtilization = performance.eventLoopUtilization();
|
|
128
|
+
let removeBatchCallback: (() => void) | undefined;
|
|
129
|
+
let disconnectGcObserver: (() => void) | undefined;
|
|
18
130
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
31
|
-
const externalGauge = meter.createObservableGauge(
|
|
32
|
-
"nodejs.memory.external_bytes",
|
|
33
|
-
{
|
|
34
|
-
description: "Memory used by C++ objects bound to JavaScript objects",
|
|
35
|
-
unit: "By",
|
|
36
|
-
},
|
|
37
|
-
);
|
|
38
|
-
const arrayBuffersGauge = meter.createObservableGauge(
|
|
39
|
-
"nodejs.memory.array_buffers_bytes",
|
|
40
|
-
{
|
|
41
|
-
description:
|
|
42
|
-
"Memory allocated for ArrayBuffers and SharedArrayBuffers (also included in external)",
|
|
131
|
+
try {
|
|
132
|
+
const heapUsedGauge = meter.createObservableGauge(
|
|
133
|
+
"nodejs.memory.heap_used_bytes",
|
|
134
|
+
{ description: "V8 heap memory used (bytes)", unit: "By" },
|
|
135
|
+
);
|
|
136
|
+
const heapTotalGauge = meter.createObservableGauge(
|
|
137
|
+
"nodejs.memory.heap_total_bytes",
|
|
138
|
+
{ description: "V8 heap memory allocated (bytes)", unit: "By" },
|
|
139
|
+
);
|
|
140
|
+
const rssGauge = meter.createObservableGauge("nodejs.memory.rss_bytes", {
|
|
141
|
+
description: "Resident Set Size - total memory allocated for the process",
|
|
43
142
|
unit: "By",
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
143
|
+
});
|
|
144
|
+
const externalGauge = meter.createObservableGauge(
|
|
145
|
+
"nodejs.memory.external_bytes",
|
|
146
|
+
{
|
|
147
|
+
description: "Memory used by C++ objects bound to JavaScript objects",
|
|
148
|
+
unit: "By",
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
const arrayBuffersGauge = meter.createObservableGauge(
|
|
152
|
+
"nodejs.memory.array_buffers_bytes",
|
|
153
|
+
{
|
|
154
|
+
description:
|
|
155
|
+
"Memory allocated for ArrayBuffers and SharedArrayBuffers (also included in external)",
|
|
156
|
+
unit: "By",
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
const heapLimitGauge = meter.createObservableGauge(
|
|
160
|
+
"nodejs.memory.heap_limit_bytes",
|
|
161
|
+
{ description: "Configured V8 heap size limit (bytes)", unit: "By" },
|
|
162
|
+
);
|
|
163
|
+
const heapUsedRatioGauge = meter.createObservableGauge(
|
|
164
|
+
"nodejs.memory.heap_used_ratio",
|
|
165
|
+
{ description: "V8 heap used divided by V8 heap size limit", unit: "1" },
|
|
166
|
+
);
|
|
167
|
+
const cgroupCurrentGauge = meter.createObservableGauge(
|
|
168
|
+
"nodejs.memory.cgroup_current_bytes",
|
|
169
|
+
{ description: "Current cgroup memory usage when available", unit: "By" },
|
|
170
|
+
);
|
|
171
|
+
const cgroupLimitGauge = meter.createObservableGauge(
|
|
172
|
+
"nodejs.memory.cgroup_limit_bytes",
|
|
173
|
+
{ description: "Cgroup memory limit when available", unit: "By" },
|
|
174
|
+
);
|
|
175
|
+
const cgroupUsageRatioGauge = meter.createObservableGauge(
|
|
176
|
+
"nodejs.memory.cgroup_usage_ratio",
|
|
177
|
+
{
|
|
178
|
+
description: "Cgroup memory usage divided by cgroup memory limit",
|
|
179
|
+
unit: "1",
|
|
180
|
+
},
|
|
181
|
+
);
|
|
182
|
+
const eventLoopDelayMeanGauge = meter.createObservableGauge(
|
|
183
|
+
"nodejs.event_loop.delay.mean_ms",
|
|
184
|
+
{
|
|
185
|
+
description: "Mean event-loop delay for the last collection window",
|
|
186
|
+
unit: "ms",
|
|
187
|
+
},
|
|
188
|
+
);
|
|
189
|
+
const eventLoopDelayMaxGauge = meter.createObservableGauge(
|
|
190
|
+
"nodejs.event_loop.delay.max_ms",
|
|
191
|
+
{
|
|
192
|
+
description: "Max event-loop delay for the last collection window",
|
|
193
|
+
unit: "ms",
|
|
194
|
+
},
|
|
195
|
+
);
|
|
196
|
+
const eventLoopDelayP50Gauge = meter.createObservableGauge(
|
|
197
|
+
"nodejs.event_loop.delay.p50_ms",
|
|
198
|
+
{
|
|
199
|
+
description: "p50 event-loop delay for the last collection window",
|
|
200
|
+
unit: "ms",
|
|
201
|
+
},
|
|
202
|
+
);
|
|
203
|
+
const eventLoopDelayP90Gauge = meter.createObservableGauge(
|
|
204
|
+
"nodejs.event_loop.delay.p90_ms",
|
|
205
|
+
{
|
|
206
|
+
description: "p90 event-loop delay for the last collection window",
|
|
207
|
+
unit: "ms",
|
|
208
|
+
},
|
|
209
|
+
);
|
|
210
|
+
const eventLoopDelayP99Gauge = meter.createObservableGauge(
|
|
211
|
+
"nodejs.event_loop.delay.p99_ms",
|
|
212
|
+
{
|
|
213
|
+
description: "p99 event-loop delay for the last collection window",
|
|
214
|
+
unit: "ms",
|
|
215
|
+
},
|
|
216
|
+
);
|
|
217
|
+
const eventLoopUtilizationGauge = meter.createObservableGauge(
|
|
218
|
+
"nodejs.event_loop.utilization",
|
|
219
|
+
{
|
|
220
|
+
description:
|
|
221
|
+
"Event-loop utilization delta for the last collection window",
|
|
222
|
+
unit: "1",
|
|
223
|
+
},
|
|
224
|
+
);
|
|
225
|
+
const processCpuUserCounter = meter.createObservableCounter(
|
|
226
|
+
"nodejs.process.cpu.user_seconds",
|
|
227
|
+
{ description: "Process user CPU time since start", unit: "s" },
|
|
228
|
+
);
|
|
229
|
+
const processCpuSystemCounter = meter.createObservableCounter(
|
|
230
|
+
"nodejs.process.cpu.system_seconds",
|
|
231
|
+
{ description: "Process system CPU time since start", unit: "s" },
|
|
232
|
+
);
|
|
69
233
|
|
|
70
|
-
|
|
234
|
+
const gcCountCounter = meter.createCounter("nodejs.gc.count", {
|
|
235
|
+
description: "Number of garbage collection events",
|
|
236
|
+
unit: "{event}",
|
|
237
|
+
});
|
|
238
|
+
const gcDurationHistogram = meter.createHistogram("nodejs.gc.duration_ms", {
|
|
239
|
+
description: "Garbage collection duration by collection kind",
|
|
240
|
+
unit: "ms",
|
|
241
|
+
advice: {
|
|
242
|
+
explicitBucketBoundaries: [0.5, 1, 2, 5, 10, 25, 50, 100, 250, 500],
|
|
243
|
+
},
|
|
244
|
+
});
|
|
71
245
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
246
|
+
const observableInstruments = [
|
|
247
|
+
heapUsedGauge,
|
|
248
|
+
heapTotalGauge,
|
|
249
|
+
rssGauge,
|
|
250
|
+
externalGauge,
|
|
251
|
+
arrayBuffersGauge,
|
|
252
|
+
heapLimitGauge,
|
|
253
|
+
heapUsedRatioGauge,
|
|
254
|
+
cgroupCurrentGauge,
|
|
255
|
+
cgroupLimitGauge,
|
|
256
|
+
cgroupUsageRatioGauge,
|
|
257
|
+
eventLoopDelayMeanGauge,
|
|
258
|
+
eventLoopDelayMaxGauge,
|
|
259
|
+
eventLoopDelayP50Gauge,
|
|
260
|
+
eventLoopDelayP90Gauge,
|
|
261
|
+
eventLoopDelayP99Gauge,
|
|
262
|
+
eventLoopUtilizationGauge,
|
|
263
|
+
processCpuUserCounter,
|
|
264
|
+
processCpuSystemCounter,
|
|
265
|
+
];
|
|
78
266
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
267
|
+
// Single callback per export interval keeps runtime stats temporally aligned.
|
|
268
|
+
const batchCb = (result: BatchObservableResult) => {
|
|
269
|
+
try {
|
|
270
|
+
const mem = process.memoryUsage();
|
|
271
|
+
const heap = getHeapStatistics();
|
|
272
|
+
const cgroup = readCgroupMemory();
|
|
273
|
+
const elu = performance.eventLoopUtilization(
|
|
274
|
+
previousEventLoopUtilization,
|
|
275
|
+
);
|
|
276
|
+
previousEventLoopUtilization = performance.eventLoopUtilization();
|
|
277
|
+
const cpu = process.cpuUsage();
|
|
278
|
+
|
|
279
|
+
result.observe(heapUsedGauge, mem.heapUsed);
|
|
280
|
+
result.observe(heapTotalGauge, mem.heapTotal);
|
|
281
|
+
result.observe(rssGauge, mem.rss);
|
|
282
|
+
result.observe(externalGauge, mem.external);
|
|
283
|
+
result.observe(arrayBuffersGauge, mem.arrayBuffers);
|
|
284
|
+
result.observe(heapLimitGauge, heap.heap_size_limit);
|
|
285
|
+
result.observe(
|
|
286
|
+
heapUsedRatioGauge,
|
|
287
|
+
ratio(mem.heapUsed, heap.heap_size_limit),
|
|
288
|
+
);
|
|
289
|
+
// Omit cgroup gauges when no finite cgroup limit is available; absence means host/unlimited memory, not telemetry setup failure.
|
|
290
|
+
if (cgroup) {
|
|
291
|
+
result.observe(cgroupCurrentGauge, cgroup.currentBytes);
|
|
292
|
+
result.observe(cgroupLimitGauge, cgroup.limitBytes);
|
|
293
|
+
result.observe(cgroupUsageRatioGauge, cgroup.usageRatio);
|
|
294
|
+
}
|
|
295
|
+
result.observe(eventLoopDelayMeanGauge, nsToMs(eventLoopDelay.mean));
|
|
296
|
+
result.observe(eventLoopDelayMaxGauge, nsToMs(eventLoopDelay.max));
|
|
297
|
+
result.observe(
|
|
298
|
+
eventLoopDelayP50Gauge,
|
|
299
|
+
nsToMs(eventLoopDelay.percentile(50)),
|
|
300
|
+
);
|
|
301
|
+
result.observe(
|
|
302
|
+
eventLoopDelayP90Gauge,
|
|
303
|
+
nsToMs(eventLoopDelay.percentile(90)),
|
|
304
|
+
);
|
|
305
|
+
result.observe(
|
|
306
|
+
eventLoopDelayP99Gauge,
|
|
307
|
+
nsToMs(eventLoopDelay.percentile(99)),
|
|
308
|
+
);
|
|
309
|
+
result.observe(
|
|
310
|
+
eventLoopUtilizationGauge,
|
|
311
|
+
finiteNonNegative(elu.utilization),
|
|
312
|
+
);
|
|
313
|
+
result.observe(processCpuUserCounter, cpu.user / US_PER_SECOND);
|
|
314
|
+
result.observe(processCpuSystemCounter, cpu.system / US_PER_SECOND);
|
|
315
|
+
} finally {
|
|
316
|
+
eventLoopDelay.reset();
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
meter.addBatchObservableCallback(batchCb, observableInstruments);
|
|
321
|
+
removeBatchCallback = () => {
|
|
322
|
+
meter.removeBatchObservableCallback(batchCb, observableInstruments);
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const gcObserver = new PerformanceObserver(
|
|
326
|
+
(list: PerformanceObserverEntryList) => {
|
|
327
|
+
for (const entry of list.getEntries() as GcPerformanceEntry[]) {
|
|
328
|
+
const kind = gcKind(entry.detail?.kind ?? entry.kind);
|
|
329
|
+
const attrs = { kind };
|
|
330
|
+
gcCountCounter.add(1, attrs);
|
|
331
|
+
gcDurationHistogram.record(finiteNonNegative(entry.duration), attrs);
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
);
|
|
335
|
+
disconnectGcObserver = () => {
|
|
336
|
+
gcObserver.disconnect();
|
|
337
|
+
};
|
|
338
|
+
gcObserver.observe({ entryTypes: ["gc"], buffered: false });
|
|
339
|
+
|
|
340
|
+
eventLoopDelay.enable();
|
|
341
|
+
cleanupFn = () => {
|
|
342
|
+
eventLoopDelay.disable();
|
|
343
|
+
disconnectGcObserver?.();
|
|
344
|
+
removeBatchCallback?.();
|
|
345
|
+
};
|
|
346
|
+
} catch (error) {
|
|
347
|
+
eventLoopDelay.disable();
|
|
348
|
+
disconnectGcObserver?.();
|
|
349
|
+
removeBatchCallback?.();
|
|
350
|
+
throw error;
|
|
351
|
+
}
|
|
83
352
|
}
|
|
84
353
|
|
|
85
354
|
export function stopMemoryMetrics(): void {
|