@checkstack/collector-hardware-backend 0.1.13 → 0.1.14
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/CHANGELOG.md +31 -0
- package/package.json +7 -7
- package/src/collectors/cpu.test.ts +5 -3
- package/src/collectors/cpu.ts +47 -21
- package/src/collectors/disk.test.ts +3 -2
- package/src/collectors/disk.ts +40 -17
- package/src/collectors/memory.test.ts +3 -2
- package/src/collectors/memory.ts +47 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# @checkstack/collector-hardware-backend
|
|
2
2
|
|
|
3
|
+
## 0.1.14
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 48c2080: Migrate aggregation from batch to incremental (`mergeResult`)
|
|
8
|
+
|
|
9
|
+
### Breaking Changes (Internal)
|
|
10
|
+
|
|
11
|
+
- Replaced `aggregateResult(runs[])` with `mergeResult(existing, run)` interface across all HealthCheckStrategy and CollectorStrategy implementations
|
|
12
|
+
|
|
13
|
+
### New Features
|
|
14
|
+
|
|
15
|
+
- Added incremental aggregation utilities in `@checkstack/backend-api`:
|
|
16
|
+
- `mergeCounter()` - track occurrences
|
|
17
|
+
- `mergeAverage()` - track sum/count, compute avg
|
|
18
|
+
- `mergeRate()` - track success/total, compute %
|
|
19
|
+
- `mergeMinMax()` - track min/max values
|
|
20
|
+
- Exported Zod schemas for internal state: `averageStateSchema`, `rateStateSchema`, `minMaxStateSchema`, `counterStateSchema`
|
|
21
|
+
|
|
22
|
+
### Improvements
|
|
23
|
+
|
|
24
|
+
- Enables O(1) storage overhead by maintaining incremental aggregation state
|
|
25
|
+
- Prepares for real-time hourly aggregation without batch accumulation
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [f676e11]
|
|
28
|
+
- Updated dependencies [48c2080]
|
|
29
|
+
- @checkstack/common@0.6.2
|
|
30
|
+
- @checkstack/backend-api@0.6.0
|
|
31
|
+
- @checkstack/healthcheck-common@0.8.2
|
|
32
|
+
- @checkstack/healthcheck-ssh-common@0.1.8
|
|
33
|
+
|
|
3
34
|
## 0.1.13
|
|
4
35
|
|
|
5
36
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/collector-hardware-backend",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
"test": "bun test"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@checkstack/backend-api": "0.5.
|
|
14
|
-
"@checkstack/common": "0.6.
|
|
15
|
-
"@checkstack/healthcheck-common": "0.
|
|
16
|
-
"@checkstack/healthcheck-ssh-common": "0.1.
|
|
13
|
+
"@checkstack/backend-api": "0.5.2",
|
|
14
|
+
"@checkstack/common": "0.6.1",
|
|
15
|
+
"@checkstack/healthcheck-common": "0.8.1",
|
|
16
|
+
"@checkstack/healthcheck-ssh-common": "0.1.7"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/bun": "^1.0.0",
|
|
20
20
|
"typescript": "^5.0.0",
|
|
21
|
-
"@checkstack/tsconfig": "0.0.
|
|
22
|
-
"@checkstack/scripts": "0.1.
|
|
21
|
+
"@checkstack/tsconfig": "0.0.3",
|
|
22
|
+
"@checkstack/scripts": "0.1.1"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -9,7 +9,7 @@ describe("CpuCollector", () => {
|
|
|
9
9
|
stat2?: { stdout: string };
|
|
10
10
|
loadavg?: { stdout: string };
|
|
11
11
|
nproc?: { stdout: string };
|
|
12
|
-
} = {}
|
|
12
|
+
} = {},
|
|
13
13
|
): SshTransportClient => {
|
|
14
14
|
let callCount = 0;
|
|
15
15
|
return {
|
|
@@ -96,7 +96,7 @@ describe("CpuCollector", () => {
|
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
-
describe("
|
|
99
|
+
describe("mergeResult", () => {
|
|
100
100
|
it("should calculate average and max CPU usage", () => {
|
|
101
101
|
const collector = new CpuCollector();
|
|
102
102
|
const runs = [
|
|
@@ -118,10 +118,12 @@ describe("CpuCollector", () => {
|
|
|
118
118
|
},
|
|
119
119
|
];
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
let aggregated = collector.mergeResult(undefined, runs[0]);
|
|
122
|
+
aggregated = collector.mergeResult(aggregated, runs[1]);
|
|
122
123
|
|
|
123
124
|
expect(aggregated.avgUsagePercent).toBe(50);
|
|
124
125
|
expect(aggregated.maxUsagePercent).toBe(75);
|
|
126
|
+
// (1.0 + 2.0) / 2 = 1.5
|
|
125
127
|
expect(aggregated.avgLoadAvg1m).toBe(1.5);
|
|
126
128
|
});
|
|
127
129
|
});
|
package/src/collectors/cpu.ts
CHANGED
|
@@ -4,6 +4,12 @@ import {
|
|
|
4
4
|
type HealthCheckRunForAggregation,
|
|
5
5
|
type CollectorResult,
|
|
6
6
|
type CollectorStrategy,
|
|
7
|
+
mergeAverage,
|
|
8
|
+
mergeMinMax,
|
|
9
|
+
averageStateSchema,
|
|
10
|
+
minMaxStateSchema,
|
|
11
|
+
type AverageState,
|
|
12
|
+
type MinMaxState,
|
|
7
13
|
} from "@checkstack/backend-api";
|
|
8
14
|
import { healthResultNumber } from "@checkstack/healthcheck-common";
|
|
9
15
|
import {
|
|
@@ -58,7 +64,7 @@ const cpuResultSchema = z.object({
|
|
|
58
64
|
|
|
59
65
|
export type CpuResult = z.infer<typeof cpuResultSchema>;
|
|
60
66
|
|
|
61
|
-
const
|
|
67
|
+
const cpuAggregatedDisplaySchema = z.object({
|
|
62
68
|
avgUsagePercent: healthResultNumber({
|
|
63
69
|
"x-chart-type": "line",
|
|
64
70
|
"x-chart-label": "Avg CPU Usage",
|
|
@@ -75,21 +81,28 @@ const cpuAggregatedSchema = z.object({
|
|
|
75
81
|
}),
|
|
76
82
|
});
|
|
77
83
|
|
|
84
|
+
const cpuAggregatedInternalSchema = z.object({
|
|
85
|
+
_usage: averageStateSchema.optional(),
|
|
86
|
+
_maxUsage: minMaxStateSchema.optional(),
|
|
87
|
+
_load: averageStateSchema.optional(),
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const cpuAggregatedSchema = cpuAggregatedDisplaySchema.merge(
|
|
91
|
+
cpuAggregatedInternalSchema,
|
|
92
|
+
);
|
|
93
|
+
|
|
78
94
|
export type CpuAggregatedResult = z.infer<typeof cpuAggregatedSchema>;
|
|
79
95
|
|
|
80
96
|
// ============================================================================
|
|
81
97
|
// CPU COLLECTOR
|
|
82
98
|
// ============================================================================
|
|
83
99
|
|
|
84
|
-
export class CpuCollector
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
CpuAggregatedResult
|
|
91
|
-
>
|
|
92
|
-
{
|
|
100
|
+
export class CpuCollector implements CollectorStrategy<
|
|
101
|
+
SshTransportClient,
|
|
102
|
+
CpuConfig,
|
|
103
|
+
CpuResult,
|
|
104
|
+
CpuAggregatedResult
|
|
105
|
+
> {
|
|
93
106
|
id = "cpu";
|
|
94
107
|
displayName = "CPU Metrics";
|
|
95
108
|
description = "Collects CPU usage, load averages, and core count via SSH";
|
|
@@ -135,21 +148,34 @@ export class CpuCollector
|
|
|
135
148
|
return { result };
|
|
136
149
|
}
|
|
137
150
|
|
|
138
|
-
|
|
139
|
-
|
|
151
|
+
mergeResult(
|
|
152
|
+
existing: CpuAggregatedResult | undefined,
|
|
153
|
+
run: HealthCheckRunForAggregation<CpuResult>,
|
|
140
154
|
): CpuAggregatedResult {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
const metadata = run.metadata;
|
|
156
|
+
|
|
157
|
+
const usageState = mergeAverage(
|
|
158
|
+
existing?._usage as AverageState | undefined,
|
|
159
|
+
metadata?.usagePercent,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const maxUsageState = mergeMinMax(
|
|
163
|
+
existing?._maxUsage as MinMaxState | undefined,
|
|
164
|
+
metadata?.usagePercent,
|
|
165
|
+
);
|
|
144
166
|
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
167
|
+
const loadState = mergeAverage(
|
|
168
|
+
existing?._load as AverageState | undefined,
|
|
169
|
+
metadata?.loadAvg1m,
|
|
170
|
+
);
|
|
148
171
|
|
|
149
172
|
return {
|
|
150
|
-
avgUsagePercent:
|
|
151
|
-
maxUsagePercent:
|
|
152
|
-
avgLoadAvg1m:
|
|
173
|
+
avgUsagePercent: usageState.avg,
|
|
174
|
+
maxUsagePercent: maxUsageState.max,
|
|
175
|
+
avgLoadAvg1m: loadState.avg,
|
|
176
|
+
_usage: usageState,
|
|
177
|
+
_maxUsage: maxUsageState,
|
|
178
|
+
_load: loadState,
|
|
153
179
|
};
|
|
154
180
|
}
|
|
155
181
|
|
|
@@ -66,7 +66,7 @@ describe("DiskCollector", () => {
|
|
|
66
66
|
});
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
describe("
|
|
69
|
+
describe("mergeResult", () => {
|
|
70
70
|
it("should calculate average and max disk usage", () => {
|
|
71
71
|
const collector = new DiskCollector();
|
|
72
72
|
const runs = [
|
|
@@ -102,7 +102,8 @@ describe("DiskCollector", () => {
|
|
|
102
102
|
},
|
|
103
103
|
];
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
let aggregated = collector.mergeResult(undefined, runs[0]);
|
|
106
|
+
aggregated = collector.mergeResult(aggregated, runs[1]);
|
|
106
107
|
|
|
107
108
|
expect(aggregated.avgUsedPercent).toBe(40);
|
|
108
109
|
expect(aggregated.maxUsedPercent).toBe(50);
|
package/src/collectors/disk.ts
CHANGED
|
@@ -4,6 +4,12 @@ import {
|
|
|
4
4
|
type HealthCheckRunForAggregation,
|
|
5
5
|
type CollectorResult,
|
|
6
6
|
type CollectorStrategy,
|
|
7
|
+
mergeAverage,
|
|
8
|
+
mergeMinMax,
|
|
9
|
+
averageStateSchema,
|
|
10
|
+
minMaxStateSchema,
|
|
11
|
+
type AverageState,
|
|
12
|
+
type MinMaxState,
|
|
7
13
|
} from "@checkstack/backend-api";
|
|
8
14
|
import {
|
|
9
15
|
healthResultNumber,
|
|
@@ -64,7 +70,7 @@ const diskResultSchema = z.object({
|
|
|
64
70
|
|
|
65
71
|
export type DiskResult = z.infer<typeof diskResultSchema>;
|
|
66
72
|
|
|
67
|
-
const
|
|
73
|
+
const diskAggregatedDisplaySchema = z.object({
|
|
68
74
|
avgUsedPercent: healthResultNumber({
|
|
69
75
|
"x-chart-type": "line",
|
|
70
76
|
"x-chart-label": "Avg Disk Usage",
|
|
@@ -77,21 +83,27 @@ const diskAggregatedSchema = z.object({
|
|
|
77
83
|
}),
|
|
78
84
|
});
|
|
79
85
|
|
|
86
|
+
const diskAggregatedInternalSchema = z.object({
|
|
87
|
+
_usage: averageStateSchema.optional(),
|
|
88
|
+
_maxUsage: minMaxStateSchema.optional(),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const diskAggregatedSchema = diskAggregatedDisplaySchema.merge(
|
|
92
|
+
diskAggregatedInternalSchema,
|
|
93
|
+
);
|
|
94
|
+
|
|
80
95
|
export type DiskAggregatedResult = z.infer<typeof diskAggregatedSchema>;
|
|
81
96
|
|
|
82
97
|
// ============================================================================
|
|
83
98
|
// DISK COLLECTOR
|
|
84
99
|
// ============================================================================
|
|
85
100
|
|
|
86
|
-
export class DiskCollector
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
DiskAggregatedResult
|
|
93
|
-
>
|
|
94
|
-
{
|
|
101
|
+
export class DiskCollector implements CollectorStrategy<
|
|
102
|
+
SshTransportClient,
|
|
103
|
+
DiskConfig,
|
|
104
|
+
DiskResult,
|
|
105
|
+
DiskAggregatedResult
|
|
106
|
+
> {
|
|
95
107
|
id = "disk";
|
|
96
108
|
displayName = "Disk Metrics";
|
|
97
109
|
description = "Collects disk usage for a specific mount point via SSH";
|
|
@@ -120,16 +132,27 @@ export class DiskCollector
|
|
|
120
132
|
return { result: parsed };
|
|
121
133
|
}
|
|
122
134
|
|
|
123
|
-
|
|
124
|
-
|
|
135
|
+
mergeResult(
|
|
136
|
+
existing: DiskAggregatedResult | undefined,
|
|
137
|
+
run: HealthCheckRunForAggregation<DiskResult>,
|
|
125
138
|
): DiskAggregatedResult {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
139
|
+
const metadata = run.metadata;
|
|
140
|
+
|
|
141
|
+
const usageState = mergeAverage(
|
|
142
|
+
existing?._usage as AverageState | undefined,
|
|
143
|
+
metadata?.usedPercent,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const maxUsageState = mergeMinMax(
|
|
147
|
+
existing?._maxUsage as MinMaxState | undefined,
|
|
148
|
+
metadata?.usedPercent,
|
|
149
|
+
);
|
|
129
150
|
|
|
130
151
|
return {
|
|
131
|
-
avgUsedPercent:
|
|
132
|
-
maxUsedPercent:
|
|
152
|
+
avgUsedPercent: usageState.avg,
|
|
153
|
+
maxUsedPercent: maxUsageState.max,
|
|
154
|
+
_usage: usageState,
|
|
155
|
+
_maxUsage: maxUsageState,
|
|
133
156
|
};
|
|
134
157
|
}
|
|
135
158
|
|
|
@@ -76,7 +76,7 @@ Swap: 4096 512 3584`
|
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
describe("
|
|
79
|
+
describe("mergeResult", () => {
|
|
80
80
|
it("should calculate average and max memory usage", () => {
|
|
81
81
|
const collector = new MemoryCollector();
|
|
82
82
|
const runs = [
|
|
@@ -108,7 +108,8 @@ Swap: 4096 512 3584`
|
|
|
108
108
|
},
|
|
109
109
|
];
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
let aggregated = collector.mergeResult(undefined, runs[0]);
|
|
112
|
+
aggregated = collector.mergeResult(aggregated, runs[1]);
|
|
112
113
|
|
|
113
114
|
expect(aggregated.avgUsedPercent).toBe(50);
|
|
114
115
|
expect(aggregated.maxUsedPercent).toBe(75);
|
package/src/collectors/memory.ts
CHANGED
|
@@ -4,6 +4,12 @@ import {
|
|
|
4
4
|
type HealthCheckRunForAggregation,
|
|
5
5
|
type CollectorResult,
|
|
6
6
|
type CollectorStrategy,
|
|
7
|
+
mergeAverage,
|
|
8
|
+
mergeMinMax,
|
|
9
|
+
averageStateSchema,
|
|
10
|
+
minMaxStateSchema,
|
|
11
|
+
type AverageState,
|
|
12
|
+
type MinMaxState,
|
|
7
13
|
} from "@checkstack/backend-api";
|
|
8
14
|
import { healthResultNumber } from "@checkstack/healthcheck-common";
|
|
9
15
|
import {
|
|
@@ -67,7 +73,7 @@ const memoryResultSchema = z.object({
|
|
|
67
73
|
|
|
68
74
|
export type MemoryResult = z.infer<typeof memoryResultSchema>;
|
|
69
75
|
|
|
70
|
-
const
|
|
76
|
+
const memoryAggregatedDisplaySchema = z.object({
|
|
71
77
|
avgUsedPercent: healthResultNumber({
|
|
72
78
|
"x-chart-type": "line",
|
|
73
79
|
"x-chart-label": "Avg Memory Usage",
|
|
@@ -85,21 +91,28 @@ const memoryAggregatedSchema = z.object({
|
|
|
85
91
|
}),
|
|
86
92
|
});
|
|
87
93
|
|
|
94
|
+
const memoryAggregatedInternalSchema = z.object({
|
|
95
|
+
_usedPercent: averageStateSchema.optional(),
|
|
96
|
+
_maxUsedPercent: minMaxStateSchema.optional(),
|
|
97
|
+
_usedMb: averageStateSchema.optional(),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const memoryAggregatedSchema = memoryAggregatedDisplaySchema.merge(
|
|
101
|
+
memoryAggregatedInternalSchema,
|
|
102
|
+
);
|
|
103
|
+
|
|
88
104
|
export type MemoryAggregatedResult = z.infer<typeof memoryAggregatedSchema>;
|
|
89
105
|
|
|
90
106
|
// ============================================================================
|
|
91
107
|
// MEMORY COLLECTOR
|
|
92
108
|
// ============================================================================
|
|
93
109
|
|
|
94
|
-
export class MemoryCollector
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
MemoryAggregatedResult
|
|
101
|
-
>
|
|
102
|
-
{
|
|
110
|
+
export class MemoryCollector implements CollectorStrategy<
|
|
111
|
+
SshTransportClient,
|
|
112
|
+
MemoryConfig,
|
|
113
|
+
MemoryResult,
|
|
114
|
+
MemoryAggregatedResult
|
|
115
|
+
> {
|
|
103
116
|
id = "memory";
|
|
104
117
|
displayName = "Memory Metrics";
|
|
105
118
|
description = "Collects RAM and swap usage via SSH";
|
|
@@ -140,21 +153,34 @@ export class MemoryCollector
|
|
|
140
153
|
return { result };
|
|
141
154
|
}
|
|
142
155
|
|
|
143
|
-
|
|
144
|
-
|
|
156
|
+
mergeResult(
|
|
157
|
+
existing: MemoryAggregatedResult | undefined,
|
|
158
|
+
run: HealthCheckRunForAggregation<MemoryResult>,
|
|
145
159
|
): MemoryAggregatedResult {
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
160
|
+
const metadata = run.metadata;
|
|
161
|
+
|
|
162
|
+
const usedPercentState = mergeAverage(
|
|
163
|
+
existing?._usedPercent as AverageState | undefined,
|
|
164
|
+
metadata?.usedPercent,
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const maxUsedPercentState = mergeMinMax(
|
|
168
|
+
existing?._maxUsedPercent as MinMaxState | undefined,
|
|
169
|
+
metadata?.usedPercent,
|
|
170
|
+
);
|
|
149
171
|
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
172
|
+
const usedMbState = mergeAverage(
|
|
173
|
+
existing?._usedMb as AverageState | undefined,
|
|
174
|
+
metadata?.usedMb,
|
|
175
|
+
);
|
|
153
176
|
|
|
154
177
|
return {
|
|
155
|
-
avgUsedPercent:
|
|
156
|
-
maxUsedPercent:
|
|
157
|
-
avgUsedMb:
|
|
178
|
+
avgUsedPercent: usedPercentState.avg,
|
|
179
|
+
maxUsedPercent: maxUsedPercentState.max,
|
|
180
|
+
avgUsedMb: usedMbState.avg,
|
|
181
|
+
_usedPercent: usedPercentState,
|
|
182
|
+
_maxUsedPercent: maxUsedPercentState,
|
|
183
|
+
_usedMb: usedMbState,
|
|
158
184
|
};
|
|
159
185
|
}
|
|
160
186
|
|