@checkstack/collector-hardware-backend 0.1.13 → 0.1.15
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 +38 -0
- package/package.json +7 -7
- package/src/collectors/cpu.test.ts +8 -6
- package/src/collectors/cpu.ts +39 -28
- package/src/collectors/disk.test.ts +5 -4
- package/src/collectors/disk.ts +35 -23
- package/src/collectors/memory.test.ts +6 -5
- package/src/collectors/memory.ts +37 -29
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# @checkstack/collector-hardware-backend
|
|
2
2
|
|
|
3
|
+
## 0.1.15
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [3dd1914]
|
|
8
|
+
- @checkstack/backend-api@0.7.0
|
|
9
|
+
|
|
10
|
+
## 0.1.14
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 48c2080: Migrate aggregation from batch to incremental (`mergeResult`)
|
|
15
|
+
|
|
16
|
+
### Breaking Changes (Internal)
|
|
17
|
+
|
|
18
|
+
- Replaced `aggregateResult(runs[])` with `mergeResult(existing, run)` interface across all HealthCheckStrategy and CollectorStrategy implementations
|
|
19
|
+
|
|
20
|
+
### New Features
|
|
21
|
+
|
|
22
|
+
- Added incremental aggregation utilities in `@checkstack/backend-api`:
|
|
23
|
+
- `mergeCounter()` - track occurrences
|
|
24
|
+
- `mergeAverage()` - track sum/count, compute avg
|
|
25
|
+
- `mergeRate()` - track success/total, compute %
|
|
26
|
+
- `mergeMinMax()` - track min/max values
|
|
27
|
+
- Exported Zod schemas for internal state: `averageStateSchema`, `rateStateSchema`, `minMaxStateSchema`, `counterStateSchema`
|
|
28
|
+
|
|
29
|
+
### Improvements
|
|
30
|
+
|
|
31
|
+
- Enables O(1) storage overhead by maintaining incremental aggregation state
|
|
32
|
+
- Prepares for real-time hourly aggregation without batch accumulation
|
|
33
|
+
|
|
34
|
+
- Updated dependencies [f676e11]
|
|
35
|
+
- Updated dependencies [48c2080]
|
|
36
|
+
- @checkstack/common@0.6.2
|
|
37
|
+
- @checkstack/backend-api@0.6.0
|
|
38
|
+
- @checkstack/healthcheck-common@0.8.2
|
|
39
|
+
- @checkstack/healthcheck-ssh-common@0.1.8
|
|
40
|
+
|
|
3
41
|
## 0.1.13
|
|
4
42
|
|
|
5
43
|
### 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.15",
|
|
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,11 +118,13 @@ 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
|
-
expect(aggregated.avgUsagePercent).toBe(50);
|
|
124
|
-
expect(aggregated.maxUsagePercent).toBe(75);
|
|
125
|
-
|
|
124
|
+
expect(aggregated.avgUsagePercent.avg).toBe(50);
|
|
125
|
+
expect(aggregated.maxUsagePercent.max).toBe(75);
|
|
126
|
+
// (1.0 + 2.0) / 2 = 1.5
|
|
127
|
+
expect(aggregated.avgLoadAvg1m.avg).toBe(1.5);
|
|
126
128
|
});
|
|
127
129
|
});
|
|
128
130
|
|
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
|
+
VersionedAggregated,
|
|
10
|
+
aggregatedAverage,
|
|
11
|
+
aggregatedMinMax,
|
|
12
|
+
type InferAggregatedResult,
|
|
7
13
|
} from "@checkstack/backend-api";
|
|
8
14
|
import { healthResultNumber } from "@checkstack/healthcheck-common";
|
|
9
15
|
import {
|
|
@@ -58,38 +64,39 @@ const cpuResultSchema = z.object({
|
|
|
58
64
|
|
|
59
65
|
export type CpuResult = z.infer<typeof cpuResultSchema>;
|
|
60
66
|
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
// Aggregated result fields definition
|
|
68
|
+
const cpuAggregatedFields = {
|
|
69
|
+
avgUsagePercent: aggregatedAverage({
|
|
63
70
|
"x-chart-type": "line",
|
|
64
71
|
"x-chart-label": "Avg CPU Usage",
|
|
65
72
|
"x-chart-unit": "%",
|
|
66
73
|
}),
|
|
67
|
-
maxUsagePercent:
|
|
74
|
+
maxUsagePercent: aggregatedMinMax({
|
|
68
75
|
"x-chart-type": "line",
|
|
69
76
|
"x-chart-label": "Max CPU Usage",
|
|
70
77
|
"x-chart-unit": "%",
|
|
71
78
|
}),
|
|
72
|
-
avgLoadAvg1m:
|
|
79
|
+
avgLoadAvg1m: aggregatedAverage({
|
|
73
80
|
"x-chart-type": "line",
|
|
74
81
|
"x-chart-label": "Avg Load (1m)",
|
|
75
82
|
}),
|
|
76
|
-
}
|
|
83
|
+
};
|
|
77
84
|
|
|
78
|
-
|
|
85
|
+
// Type inferred from field definitions
|
|
86
|
+
export type CpuAggregatedResult = InferAggregatedResult<
|
|
87
|
+
typeof cpuAggregatedFields
|
|
88
|
+
>;
|
|
79
89
|
|
|
80
90
|
// ============================================================================
|
|
81
91
|
// CPU COLLECTOR
|
|
82
92
|
// ============================================================================
|
|
83
93
|
|
|
84
|
-
export class CpuCollector
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
CpuAggregatedResult
|
|
91
|
-
>
|
|
92
|
-
{
|
|
94
|
+
export class CpuCollector implements CollectorStrategy<
|
|
95
|
+
SshTransportClient,
|
|
96
|
+
CpuConfig,
|
|
97
|
+
CpuResult,
|
|
98
|
+
CpuAggregatedResult
|
|
99
|
+
> {
|
|
93
100
|
id = "cpu";
|
|
94
101
|
displayName = "CPU Metrics";
|
|
95
102
|
description = "Collects CPU usage, load averages, and core count via SSH";
|
|
@@ -98,7 +105,10 @@ export class CpuCollector
|
|
|
98
105
|
|
|
99
106
|
config = new Versioned({ version: 1, schema: cpuConfigSchema });
|
|
100
107
|
result = new Versioned({ version: 1, schema: cpuResultSchema });
|
|
101
|
-
aggregatedResult = new
|
|
108
|
+
aggregatedResult = new VersionedAggregated({
|
|
109
|
+
version: 1,
|
|
110
|
+
fields: cpuAggregatedFields,
|
|
111
|
+
});
|
|
102
112
|
|
|
103
113
|
async execute({
|
|
104
114
|
config,
|
|
@@ -135,21 +145,22 @@ export class CpuCollector
|
|
|
135
145
|
return { result };
|
|
136
146
|
}
|
|
137
147
|
|
|
138
|
-
|
|
139
|
-
|
|
148
|
+
mergeResult(
|
|
149
|
+
existing: CpuAggregatedResult | undefined,
|
|
150
|
+
run: HealthCheckRunForAggregation<CpuResult>,
|
|
140
151
|
): CpuAggregatedResult {
|
|
141
|
-
const
|
|
142
|
-
.map((r) => r.metadata?.usagePercent)
|
|
143
|
-
.filter((v): v is number => typeof v === "number");
|
|
144
|
-
|
|
145
|
-
const loads = runs
|
|
146
|
-
.map((r) => r.metadata?.loadAvg1m)
|
|
147
|
-
.filter((v): v is number => typeof v === "number");
|
|
152
|
+
const metadata = run.metadata;
|
|
148
153
|
|
|
149
154
|
return {
|
|
150
|
-
avgUsagePercent:
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
avgUsagePercent: mergeAverage(
|
|
156
|
+
existing?.avgUsagePercent,
|
|
157
|
+
metadata?.usagePercent,
|
|
158
|
+
),
|
|
159
|
+
maxUsagePercent: mergeMinMax(
|
|
160
|
+
existing?.maxUsagePercent,
|
|
161
|
+
metadata?.usagePercent,
|
|
162
|
+
),
|
|
163
|
+
avgLoadAvg1m: mergeAverage(existing?.avgLoadAvg1m, metadata?.loadAvg1m),
|
|
153
164
|
};
|
|
154
165
|
}
|
|
155
166
|
|
|
@@ -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,10 +102,11 @@ 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
|
-
expect(aggregated.avgUsedPercent).toBe(40);
|
|
108
|
-
expect(aggregated.maxUsedPercent).toBe(50);
|
|
108
|
+
expect(aggregated.avgUsedPercent.avg).toBe(40);
|
|
109
|
+
expect(aggregated.maxUsedPercent.max).toBe(50);
|
|
109
110
|
});
|
|
110
111
|
});
|
|
111
112
|
|
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
|
+
VersionedAggregated,
|
|
10
|
+
aggregatedAverage,
|
|
11
|
+
aggregatedMinMax,
|
|
12
|
+
type InferAggregatedResult,
|
|
7
13
|
} from "@checkstack/backend-api";
|
|
8
14
|
import {
|
|
9
15
|
healthResultNumber,
|
|
@@ -64,34 +70,35 @@ const diskResultSchema = z.object({
|
|
|
64
70
|
|
|
65
71
|
export type DiskResult = z.infer<typeof diskResultSchema>;
|
|
66
72
|
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
// Aggregated result fields definition
|
|
74
|
+
const diskAggregatedFields = {
|
|
75
|
+
avgUsedPercent: aggregatedAverage({
|
|
69
76
|
"x-chart-type": "line",
|
|
70
77
|
"x-chart-label": "Avg Disk Usage",
|
|
71
78
|
"x-chart-unit": "%",
|
|
72
79
|
}),
|
|
73
|
-
maxUsedPercent:
|
|
80
|
+
maxUsedPercent: aggregatedMinMax({
|
|
74
81
|
"x-chart-type": "line",
|
|
75
82
|
"x-chart-label": "Max Disk Usage",
|
|
76
83
|
"x-chart-unit": "%",
|
|
77
84
|
}),
|
|
78
|
-
}
|
|
85
|
+
};
|
|
79
86
|
|
|
80
|
-
|
|
87
|
+
// Type inferred from field definitions
|
|
88
|
+
export type DiskAggregatedResult = InferAggregatedResult<
|
|
89
|
+
typeof diskAggregatedFields
|
|
90
|
+
>;
|
|
81
91
|
|
|
82
92
|
// ============================================================================
|
|
83
93
|
// DISK COLLECTOR
|
|
84
94
|
// ============================================================================
|
|
85
95
|
|
|
86
|
-
export class DiskCollector
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
DiskAggregatedResult
|
|
93
|
-
>
|
|
94
|
-
{
|
|
96
|
+
export class DiskCollector implements CollectorStrategy<
|
|
97
|
+
SshTransportClient,
|
|
98
|
+
DiskConfig,
|
|
99
|
+
DiskResult,
|
|
100
|
+
DiskAggregatedResult
|
|
101
|
+
> {
|
|
95
102
|
id = "disk";
|
|
96
103
|
displayName = "Disk Metrics";
|
|
97
104
|
description = "Collects disk usage for a specific mount point via SSH";
|
|
@@ -100,9 +107,9 @@ export class DiskCollector
|
|
|
100
107
|
|
|
101
108
|
config = new Versioned({ version: 1, schema: diskConfigSchema });
|
|
102
109
|
result = new Versioned({ version: 1, schema: diskResultSchema });
|
|
103
|
-
aggregatedResult = new
|
|
110
|
+
aggregatedResult = new VersionedAggregated({
|
|
104
111
|
version: 1,
|
|
105
|
-
|
|
112
|
+
fields: diskAggregatedFields,
|
|
106
113
|
});
|
|
107
114
|
|
|
108
115
|
async execute({
|
|
@@ -120,16 +127,21 @@ export class DiskCollector
|
|
|
120
127
|
return { result: parsed };
|
|
121
128
|
}
|
|
122
129
|
|
|
123
|
-
|
|
124
|
-
|
|
130
|
+
mergeResult(
|
|
131
|
+
existing: DiskAggregatedResult | undefined,
|
|
132
|
+
run: HealthCheckRunForAggregation<DiskResult>,
|
|
125
133
|
): DiskAggregatedResult {
|
|
126
|
-
const
|
|
127
|
-
.map((r) => r.metadata?.usedPercent)
|
|
128
|
-
.filter((v): v is number => typeof v === "number");
|
|
134
|
+
const metadata = run.metadata;
|
|
129
135
|
|
|
130
136
|
return {
|
|
131
|
-
avgUsedPercent:
|
|
132
|
-
|
|
137
|
+
avgUsedPercent: mergeAverage(
|
|
138
|
+
existing?.avgUsedPercent,
|
|
139
|
+
metadata?.usedPercent,
|
|
140
|
+
),
|
|
141
|
+
maxUsedPercent: mergeMinMax(
|
|
142
|
+
existing?.maxUsedPercent,
|
|
143
|
+
metadata?.usedPercent,
|
|
144
|
+
),
|
|
133
145
|
};
|
|
134
146
|
}
|
|
135
147
|
|
|
@@ -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,11 +108,12 @@ 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
|
-
expect(aggregated.avgUsedPercent).toBe(50);
|
|
114
|
-
expect(aggregated.maxUsedPercent).toBe(75);
|
|
115
|
-
expect(aggregated.avgUsedMb).toBe(8000);
|
|
114
|
+
expect(aggregated.avgUsedPercent.avg).toBe(50);
|
|
115
|
+
expect(aggregated.maxUsedPercent.max).toBe(75);
|
|
116
|
+
expect(aggregated.avgUsedMb.avg).toBe(8000);
|
|
116
117
|
});
|
|
117
118
|
});
|
|
118
119
|
|
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
|
+
VersionedAggregated,
|
|
10
|
+
aggregatedAverage,
|
|
11
|
+
aggregatedMinMax,
|
|
12
|
+
type InferAggregatedResult,
|
|
7
13
|
} from "@checkstack/backend-api";
|
|
8
14
|
import { healthResultNumber } from "@checkstack/healthcheck-common";
|
|
9
15
|
import {
|
|
@@ -67,39 +73,40 @@ const memoryResultSchema = z.object({
|
|
|
67
73
|
|
|
68
74
|
export type MemoryResult = z.infer<typeof memoryResultSchema>;
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
// Aggregated result fields definition
|
|
77
|
+
const memoryAggregatedFields = {
|
|
78
|
+
avgUsedPercent: aggregatedAverage({
|
|
72
79
|
"x-chart-type": "line",
|
|
73
80
|
"x-chart-label": "Avg Memory Usage",
|
|
74
81
|
"x-chart-unit": "%",
|
|
75
82
|
}),
|
|
76
|
-
maxUsedPercent:
|
|
83
|
+
maxUsedPercent: aggregatedMinMax({
|
|
77
84
|
"x-chart-type": "line",
|
|
78
85
|
"x-chart-label": "Max Memory Usage",
|
|
79
86
|
"x-chart-unit": "%",
|
|
80
87
|
}),
|
|
81
|
-
avgUsedMb:
|
|
88
|
+
avgUsedMb: aggregatedAverage({
|
|
82
89
|
"x-chart-type": "line",
|
|
83
90
|
"x-chart-label": "Avg Memory Used",
|
|
84
91
|
"x-chart-unit": "MB",
|
|
85
92
|
}),
|
|
86
|
-
}
|
|
93
|
+
};
|
|
87
94
|
|
|
88
|
-
|
|
95
|
+
// Type inferred from field definitions
|
|
96
|
+
export type MemoryAggregatedResult = InferAggregatedResult<
|
|
97
|
+
typeof memoryAggregatedFields
|
|
98
|
+
>;
|
|
89
99
|
|
|
90
100
|
// ============================================================================
|
|
91
101
|
// MEMORY COLLECTOR
|
|
92
102
|
// ============================================================================
|
|
93
103
|
|
|
94
|
-
export class MemoryCollector
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
MemoryAggregatedResult
|
|
101
|
-
>
|
|
102
|
-
{
|
|
104
|
+
export class MemoryCollector implements CollectorStrategy<
|
|
105
|
+
SshTransportClient,
|
|
106
|
+
MemoryConfig,
|
|
107
|
+
MemoryResult,
|
|
108
|
+
MemoryAggregatedResult
|
|
109
|
+
> {
|
|
103
110
|
id = "memory";
|
|
104
111
|
displayName = "Memory Metrics";
|
|
105
112
|
description = "Collects RAM and swap usage via SSH";
|
|
@@ -108,9 +115,9 @@ export class MemoryCollector
|
|
|
108
115
|
|
|
109
116
|
config = new Versioned({ version: 1, schema: memoryConfigSchema });
|
|
110
117
|
result = new Versioned({ version: 1, schema: memoryResultSchema });
|
|
111
|
-
aggregatedResult = new
|
|
118
|
+
aggregatedResult = new VersionedAggregated({
|
|
112
119
|
version: 1,
|
|
113
|
-
|
|
120
|
+
fields: memoryAggregatedFields,
|
|
114
121
|
});
|
|
115
122
|
|
|
116
123
|
async execute({
|
|
@@ -140,21 +147,22 @@ export class MemoryCollector
|
|
|
140
147
|
return { result };
|
|
141
148
|
}
|
|
142
149
|
|
|
143
|
-
|
|
144
|
-
|
|
150
|
+
mergeResult(
|
|
151
|
+
existing: MemoryAggregatedResult | undefined,
|
|
152
|
+
run: HealthCheckRunForAggregation<MemoryResult>,
|
|
145
153
|
): MemoryAggregatedResult {
|
|
146
|
-
const
|
|
147
|
-
.map((r) => r.metadata?.usedPercent)
|
|
148
|
-
.filter((v): v is number => typeof v === "number");
|
|
149
|
-
|
|
150
|
-
const usedMbs = runs
|
|
151
|
-
.map((r) => r.metadata?.usedMb)
|
|
152
|
-
.filter((v): v is number => typeof v === "number");
|
|
154
|
+
const metadata = run.metadata;
|
|
153
155
|
|
|
154
156
|
return {
|
|
155
|
-
avgUsedPercent:
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
avgUsedPercent: mergeAverage(
|
|
158
|
+
existing?.avgUsedPercent,
|
|
159
|
+
metadata?.usedPercent,
|
|
160
|
+
),
|
|
161
|
+
maxUsedPercent: mergeMinMax(
|
|
162
|
+
existing?.maxUsedPercent,
|
|
163
|
+
metadata?.usedPercent,
|
|
164
|
+
),
|
|
165
|
+
avgUsedMb: mergeAverage(existing?.avgUsedMb, metadata?.usedMb),
|
|
158
166
|
};
|
|
159
167
|
}
|
|
160
168
|
|