@zucker-framework/monitoring 1.0.0
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 +201 -0
- package/NOTICE +22 -0
- package/THIRD_PARTY_NOTICES +4 -0
- package/dist/index.d.mts +502 -0
- package/dist/index.d.ts +502 -0
- package/dist/index.js +1748 -0
- package/dist/index.mjs +1690 -0
- package/package.json +38 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1748 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
AlertController: () => AlertController,
|
|
35
|
+
AlertManagerService: () => AlertManagerService,
|
|
36
|
+
Counter: () => Counter,
|
|
37
|
+
ERROR_REPORTER: () => ERROR_REPORTER,
|
|
38
|
+
ErrorTracker: () => ErrorTracker,
|
|
39
|
+
Gauge: () => Gauge,
|
|
40
|
+
HEALTH_OPTIONS: () => HEALTH_OPTIONS,
|
|
41
|
+
HealthCheckService: () => HealthCheckService,
|
|
42
|
+
HealthController: () => HealthController,
|
|
43
|
+
HealthStatus: () => HealthStatus,
|
|
44
|
+
Histogram: () => Histogram,
|
|
45
|
+
InMemoryMetricsCollector: () => InMemoryMetricsCollector,
|
|
46
|
+
METRICS_COLLECTOR: () => METRICS_COLLECTOR,
|
|
47
|
+
Metrics: () => Metrics,
|
|
48
|
+
MetricsRegistry: () => MetricsRegistry,
|
|
49
|
+
NoopErrorReporter: () => NoopErrorReporter,
|
|
50
|
+
PrometheusExporter: () => PrometheusExporter,
|
|
51
|
+
Summary: () => Summary,
|
|
52
|
+
SystemMetricsCollector: () => SystemMetricsCollector,
|
|
53
|
+
Timer: () => Timer,
|
|
54
|
+
UsageTracker: () => UsageTracker,
|
|
55
|
+
ZuckerMonitoringModule: () => ZuckerMonitoringModule,
|
|
56
|
+
getProcessUptime: () => getProcessUptime,
|
|
57
|
+
renderPrometheusMetrics: () => renderPrometheusMetrics
|
|
58
|
+
});
|
|
59
|
+
module.exports = __toCommonJS(index_exports);
|
|
60
|
+
|
|
61
|
+
// src/error-tracker.ts
|
|
62
|
+
var import_common = require("@nestjs/common");
|
|
63
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
64
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
65
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
66
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
67
|
+
} else {
|
|
68
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
69
|
+
if (d = decorators[i]) {
|
|
70
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
75
|
+
}
|
|
76
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
77
|
+
var ErrorTracker = class _ErrorTracker {
|
|
78
|
+
static {
|
|
79
|
+
__name(this, "ErrorTracker");
|
|
80
|
+
}
|
|
81
|
+
logger = new import_common.Logger(_ErrorTracker.name);
|
|
82
|
+
errors = /* @__PURE__ */ new Map();
|
|
83
|
+
counter = 0;
|
|
84
|
+
track(error, category = "unknown", metadata) {
|
|
85
|
+
const key = `${category}:${error.message}`;
|
|
86
|
+
const existing = this.errors.get(key);
|
|
87
|
+
if (existing) {
|
|
88
|
+
existing.count++;
|
|
89
|
+
existing.lastOccurrence = /* @__PURE__ */ new Date();
|
|
90
|
+
if (metadata) {
|
|
91
|
+
existing.metadata = {
|
|
92
|
+
...existing.metadata,
|
|
93
|
+
...metadata
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
this.errors.set(key, {
|
|
98
|
+
id: `err_${++this.counter}`,
|
|
99
|
+
message: error.message,
|
|
100
|
+
stack: error.stack,
|
|
101
|
+
category,
|
|
102
|
+
count: 1,
|
|
103
|
+
firstOccurrence: /* @__PURE__ */ new Date(),
|
|
104
|
+
lastOccurrence: /* @__PURE__ */ new Date(),
|
|
105
|
+
metadata
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
this.logger.warn(`[${category}] ${error.message} (count: ${this.errors.get(key).count})`);
|
|
109
|
+
}
|
|
110
|
+
getErrors() {
|
|
111
|
+
return Array.from(this.errors.values());
|
|
112
|
+
}
|
|
113
|
+
getErrorsByCategory(category) {
|
|
114
|
+
return this.getErrors().filter((e) => e.category === category);
|
|
115
|
+
}
|
|
116
|
+
getTopErrors(limit = 10) {
|
|
117
|
+
return this.getErrors().sort((a, b) => b.count - a.count).slice(0, limit);
|
|
118
|
+
}
|
|
119
|
+
clear() {
|
|
120
|
+
this.errors.clear();
|
|
121
|
+
}
|
|
122
|
+
clearCategory(category) {
|
|
123
|
+
for (const [key, error] of this.errors) {
|
|
124
|
+
if (error.category === category) {
|
|
125
|
+
this.errors.delete(key);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
ErrorTracker = _ts_decorate([
|
|
131
|
+
(0, import_common.Injectable)()
|
|
132
|
+
], ErrorTracker);
|
|
133
|
+
|
|
134
|
+
// src/error-reporter.ts
|
|
135
|
+
var ERROR_REPORTER = /* @__PURE__ */ Symbol.for("@zucker-framework/monitoring/error-reporter");
|
|
136
|
+
var NoopErrorReporter = class {
|
|
137
|
+
static {
|
|
138
|
+
__name(this, "NoopErrorReporter");
|
|
139
|
+
}
|
|
140
|
+
captureException() {
|
|
141
|
+
}
|
|
142
|
+
captureMessage() {
|
|
143
|
+
}
|
|
144
|
+
setUser() {
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// src/health-check.service.ts
|
|
149
|
+
var import_common2 = require("@nestjs/common");
|
|
150
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
151
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
152
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
153
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
154
|
+
} else {
|
|
155
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
156
|
+
if (d = decorators[i]) {
|
|
157
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
162
|
+
}
|
|
163
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
164
|
+
var HealthStatus = /* @__PURE__ */ (function(HealthStatus2) {
|
|
165
|
+
HealthStatus2["UP"] = "UP";
|
|
166
|
+
HealthStatus2["DOWN"] = "DOWN";
|
|
167
|
+
HealthStatus2["DEGRADED"] = "DEGRADED";
|
|
168
|
+
return HealthStatus2;
|
|
169
|
+
})({});
|
|
170
|
+
var HealthCheckService = class _HealthCheckService {
|
|
171
|
+
static {
|
|
172
|
+
__name(this, "HealthCheckService");
|
|
173
|
+
}
|
|
174
|
+
logger = new import_common2.Logger(_HealthCheckService.name);
|
|
175
|
+
indicators = [];
|
|
176
|
+
registerIndicator(indicator) {
|
|
177
|
+
this.indicators.push(indicator);
|
|
178
|
+
this.logger.log(`Health indicator registered: ${indicator.name}`);
|
|
179
|
+
}
|
|
180
|
+
unregisterIndicator(name) {
|
|
181
|
+
this.indicators = this.indicators.filter((i) => i.name !== name);
|
|
182
|
+
}
|
|
183
|
+
async checkAll() {
|
|
184
|
+
const checks = [];
|
|
185
|
+
let overallStatus = "UP";
|
|
186
|
+
for (const indicator of this.indicators) {
|
|
187
|
+
try {
|
|
188
|
+
const result = await indicator.check();
|
|
189
|
+
checks.push(result);
|
|
190
|
+
if (result.status === "DOWN") {
|
|
191
|
+
overallStatus = "DOWN";
|
|
192
|
+
} else if (result.status === "DEGRADED" && overallStatus !== "DOWN") {
|
|
193
|
+
overallStatus = "DEGRADED";
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
const errorType = error instanceof Error ? error.name : "UnknownError";
|
|
197
|
+
this.logger.warn(`Health indicator failed: ${indicator.name} (${errorType})`);
|
|
198
|
+
checks.push({
|
|
199
|
+
name: indicator.name,
|
|
200
|
+
status: "DOWN",
|
|
201
|
+
details: {
|
|
202
|
+
error: "Health check failed"
|
|
203
|
+
},
|
|
204
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
205
|
+
});
|
|
206
|
+
overallStatus = "DOWN";
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
status: overallStatus,
|
|
211
|
+
checks,
|
|
212
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
async check(name) {
|
|
216
|
+
const indicator = this.indicators.find((i) => i.name === name);
|
|
217
|
+
if (!indicator) return void 0;
|
|
218
|
+
return indicator.check();
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
HealthCheckService = _ts_decorate2([
|
|
222
|
+
(0, import_common2.Injectable)()
|
|
223
|
+
], HealthCheckService);
|
|
224
|
+
|
|
225
|
+
// src/metrics-legacy.ts
|
|
226
|
+
var InMemoryMetricsCollector = class _InMemoryMetricsCollector {
|
|
227
|
+
static {
|
|
228
|
+
__name(this, "InMemoryMetricsCollector");
|
|
229
|
+
}
|
|
230
|
+
metrics = [];
|
|
231
|
+
static sortedTagsKey(tags) {
|
|
232
|
+
const sortedKeys = Object.keys(tags).sort();
|
|
233
|
+
const sorted = {};
|
|
234
|
+
for (const k of sortedKeys) {
|
|
235
|
+
sorted[k] = tags[k];
|
|
236
|
+
}
|
|
237
|
+
return JSON.stringify(sorted);
|
|
238
|
+
}
|
|
239
|
+
increment(name, tags = {}) {
|
|
240
|
+
const tagsKey = _InMemoryMetricsCollector.sortedTagsKey(tags);
|
|
241
|
+
const existing = this.metrics.find((m) => m.name === name && _InMemoryMetricsCollector.sortedTagsKey(m.tags) === tagsKey);
|
|
242
|
+
if (existing) {
|
|
243
|
+
existing.value++;
|
|
244
|
+
existing.timestamp = /* @__PURE__ */ new Date();
|
|
245
|
+
} else {
|
|
246
|
+
this.metrics.push({
|
|
247
|
+
name,
|
|
248
|
+
value: 1,
|
|
249
|
+
tags,
|
|
250
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
gauge(name, value, tags = {}) {
|
|
255
|
+
const tagsKey = _InMemoryMetricsCollector.sortedTagsKey(tags);
|
|
256
|
+
const existing = this.metrics.find((m) => m.name === name && _InMemoryMetricsCollector.sortedTagsKey(m.tags) === tagsKey);
|
|
257
|
+
if (existing) {
|
|
258
|
+
existing.value = value;
|
|
259
|
+
existing.timestamp = /* @__PURE__ */ new Date();
|
|
260
|
+
} else {
|
|
261
|
+
this.metrics.push({
|
|
262
|
+
name,
|
|
263
|
+
value,
|
|
264
|
+
tags,
|
|
265
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
histogram(name, value, tags = {}) {
|
|
270
|
+
this.metrics.push({
|
|
271
|
+
name,
|
|
272
|
+
value,
|
|
273
|
+
tags,
|
|
274
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
getMetrics() {
|
|
278
|
+
return [
|
|
279
|
+
...this.metrics
|
|
280
|
+
];
|
|
281
|
+
}
|
|
282
|
+
clear() {
|
|
283
|
+
this.metrics = [];
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// src/metrics/metrics-registry.ts
|
|
288
|
+
var import_common3 = require("@nestjs/common");
|
|
289
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
290
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
291
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
292
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
293
|
+
} else {
|
|
294
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
295
|
+
if (d = decorators[i]) {
|
|
296
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
301
|
+
}
|
|
302
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
303
|
+
function normalizeLabels(labels) {
|
|
304
|
+
return Object.fromEntries(Object.entries(labels).sort(([a], [b]) => a.localeCompare(b)));
|
|
305
|
+
}
|
|
306
|
+
__name(normalizeLabels, "normalizeLabels");
|
|
307
|
+
function serializeLabels(labels) {
|
|
308
|
+
return JSON.stringify(normalizeLabels(labels));
|
|
309
|
+
}
|
|
310
|
+
__name(serializeLabels, "serializeLabels");
|
|
311
|
+
function deserializeLabels(key) {
|
|
312
|
+
if (!key) return {};
|
|
313
|
+
return JSON.parse(key);
|
|
314
|
+
}
|
|
315
|
+
__name(deserializeLabels, "deserializeLabels");
|
|
316
|
+
var Counter = class {
|
|
317
|
+
static {
|
|
318
|
+
__name(this, "Counter");
|
|
319
|
+
}
|
|
320
|
+
name;
|
|
321
|
+
description;
|
|
322
|
+
values = /* @__PURE__ */ new Map();
|
|
323
|
+
constructor(name, description) {
|
|
324
|
+
this.name = name;
|
|
325
|
+
this.description = description;
|
|
326
|
+
}
|
|
327
|
+
increment(labels = {}, amount = 1) {
|
|
328
|
+
const key = this.labelsKey(labels);
|
|
329
|
+
this.values.set(key, (this.values.get(key) ?? 0) + amount);
|
|
330
|
+
}
|
|
331
|
+
get(labels = {}) {
|
|
332
|
+
return this.values.get(this.labelsKey(labels)) ?? 0;
|
|
333
|
+
}
|
|
334
|
+
getAll() {
|
|
335
|
+
return Array.from(this.values.entries()).map(([key, value]) => ({
|
|
336
|
+
labels: this.parseKey(key),
|
|
337
|
+
value
|
|
338
|
+
}));
|
|
339
|
+
}
|
|
340
|
+
labelsKey(labels) {
|
|
341
|
+
return serializeLabels(labels);
|
|
342
|
+
}
|
|
343
|
+
parseKey(key) {
|
|
344
|
+
return deserializeLabels(key);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
var Gauge = class {
|
|
348
|
+
static {
|
|
349
|
+
__name(this, "Gauge");
|
|
350
|
+
}
|
|
351
|
+
name;
|
|
352
|
+
description;
|
|
353
|
+
values = /* @__PURE__ */ new Map();
|
|
354
|
+
constructor(name, description) {
|
|
355
|
+
this.name = name;
|
|
356
|
+
this.description = description;
|
|
357
|
+
}
|
|
358
|
+
set(value, labels = {}) {
|
|
359
|
+
this.values.set(this.labelsKey(labels), value);
|
|
360
|
+
}
|
|
361
|
+
get(labels = {}) {
|
|
362
|
+
return this.values.get(this.labelsKey(labels)) ?? 0;
|
|
363
|
+
}
|
|
364
|
+
increment(labels = {}, amount = 1) {
|
|
365
|
+
const key = this.labelsKey(labels);
|
|
366
|
+
this.values.set(key, (this.values.get(key) ?? 0) + amount);
|
|
367
|
+
}
|
|
368
|
+
decrement(labels = {}, amount = 1) {
|
|
369
|
+
const key = this.labelsKey(labels);
|
|
370
|
+
this.values.set(key, (this.values.get(key) ?? 0) - amount);
|
|
371
|
+
}
|
|
372
|
+
getAll() {
|
|
373
|
+
return Array.from(this.values.entries()).map(([key, value]) => ({
|
|
374
|
+
labels: this.parseKey(key),
|
|
375
|
+
value
|
|
376
|
+
}));
|
|
377
|
+
}
|
|
378
|
+
labelsKey(labels) {
|
|
379
|
+
return serializeLabels(labels);
|
|
380
|
+
}
|
|
381
|
+
parseKey(key) {
|
|
382
|
+
return deserializeLabels(key);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
var Histogram = class {
|
|
386
|
+
static {
|
|
387
|
+
__name(this, "Histogram");
|
|
388
|
+
}
|
|
389
|
+
name;
|
|
390
|
+
description;
|
|
391
|
+
buckets;
|
|
392
|
+
maxSamples;
|
|
393
|
+
observations = /* @__PURE__ */ new Map();
|
|
394
|
+
constructor(name, description, buckets = [
|
|
395
|
+
5e-3,
|
|
396
|
+
0.01,
|
|
397
|
+
0.025,
|
|
398
|
+
0.05,
|
|
399
|
+
0.1,
|
|
400
|
+
0.25,
|
|
401
|
+
0.5,
|
|
402
|
+
1,
|
|
403
|
+
2.5,
|
|
404
|
+
5,
|
|
405
|
+
10
|
|
406
|
+
], maxSamples = 1e4) {
|
|
407
|
+
this.name = name;
|
|
408
|
+
this.description = description;
|
|
409
|
+
this.buckets = buckets;
|
|
410
|
+
this.maxSamples = maxSamples;
|
|
411
|
+
if (!Number.isInteger(maxSamples) || maxSamples <= 0) {
|
|
412
|
+
throw new Error("Histogram maxSamples must be a positive integer");
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
observe(value, labels = {}) {
|
|
416
|
+
const key = this.labelsKey(labels);
|
|
417
|
+
const observation = this.observations.get(key) ?? {
|
|
418
|
+
count: 0,
|
|
419
|
+
sum: 0,
|
|
420
|
+
bucketCounts: this.buckets.map(() => 0),
|
|
421
|
+
samples: []
|
|
422
|
+
};
|
|
423
|
+
observation.count += 1;
|
|
424
|
+
observation.sum += value;
|
|
425
|
+
for (let index = 0; index < this.buckets.length; index += 1) {
|
|
426
|
+
if (value <= this.buckets[index]) observation.bucketCounts[index] += 1;
|
|
427
|
+
}
|
|
428
|
+
observation.samples.push(value);
|
|
429
|
+
if (observation.samples.length > this.maxSamples) {
|
|
430
|
+
observation.samples.splice(0, observation.samples.length - this.maxSamples);
|
|
431
|
+
}
|
|
432
|
+
this.observations.set(key, observation);
|
|
433
|
+
}
|
|
434
|
+
getPercentile(percentile, labels = {}) {
|
|
435
|
+
const values = this.observations.get(this.labelsKey(labels))?.samples ?? [];
|
|
436
|
+
if (values.length === 0) return 0;
|
|
437
|
+
const sorted = [
|
|
438
|
+
...values
|
|
439
|
+
].sort((a, b) => a - b);
|
|
440
|
+
const idx = Math.ceil(percentile / 100 * sorted.length) - 1;
|
|
441
|
+
return sorted[Math.max(0, idx)];
|
|
442
|
+
}
|
|
443
|
+
getCount(labels = {}) {
|
|
444
|
+
return this.observations.get(this.labelsKey(labels))?.count ?? 0;
|
|
445
|
+
}
|
|
446
|
+
getSum(labels = {}) {
|
|
447
|
+
return this.observations.get(this.labelsKey(labels))?.sum ?? 0;
|
|
448
|
+
}
|
|
449
|
+
getAll() {
|
|
450
|
+
return Array.from(this.observations.entries()).map(([key, observation]) => {
|
|
451
|
+
const bucketCounts = {};
|
|
452
|
+
for (let index = 0; index < this.buckets.length; index += 1) {
|
|
453
|
+
bucketCounts[String(this.buckets[index])] = observation.bucketCounts[index];
|
|
454
|
+
}
|
|
455
|
+
bucketCounts["+Inf"] = observation.count;
|
|
456
|
+
return {
|
|
457
|
+
labels: this.parseKey(key),
|
|
458
|
+
count: observation.count,
|
|
459
|
+
sum: observation.sum,
|
|
460
|
+
bucketCounts
|
|
461
|
+
};
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
labelsKey(labels) {
|
|
465
|
+
return serializeLabels(labels);
|
|
466
|
+
}
|
|
467
|
+
parseKey(key) {
|
|
468
|
+
return deserializeLabels(key);
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
var Timer = class {
|
|
472
|
+
static {
|
|
473
|
+
__name(this, "Timer");
|
|
474
|
+
}
|
|
475
|
+
name;
|
|
476
|
+
description;
|
|
477
|
+
histogram;
|
|
478
|
+
constructor(name, description) {
|
|
479
|
+
this.name = name;
|
|
480
|
+
this.description = description;
|
|
481
|
+
this.histogram = new Histogram(name, description);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* 记录一次耗时(秒)
|
|
485
|
+
*/
|
|
486
|
+
record(durationSeconds, labels = {}) {
|
|
487
|
+
this.histogram.observe(durationSeconds, labels);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* 开始计时,返回结束函数
|
|
491
|
+
*/
|
|
492
|
+
startTimer(labels = {}) {
|
|
493
|
+
const start = process.hrtime.bigint();
|
|
494
|
+
return () => {
|
|
495
|
+
const duration = Number(process.hrtime.bigint() - start) / 1e9;
|
|
496
|
+
this.record(duration, labels);
|
|
497
|
+
return duration;
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
getHistogram() {
|
|
501
|
+
return this.histogram;
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
var Summary = class {
|
|
505
|
+
static {
|
|
506
|
+
__name(this, "Summary");
|
|
507
|
+
}
|
|
508
|
+
name;
|
|
509
|
+
description;
|
|
510
|
+
quantiles;
|
|
511
|
+
maxAgeMs;
|
|
512
|
+
maxSamples;
|
|
513
|
+
observations = /* @__PURE__ */ new Map();
|
|
514
|
+
constructor(name, description, quantiles = [
|
|
515
|
+
0.5,
|
|
516
|
+
0.9,
|
|
517
|
+
0.95,
|
|
518
|
+
0.99
|
|
519
|
+
], maxAgeMs = 6e5, maxSamples = 1e4) {
|
|
520
|
+
this.name = name;
|
|
521
|
+
this.description = description;
|
|
522
|
+
this.quantiles = quantiles;
|
|
523
|
+
this.maxAgeMs = maxAgeMs;
|
|
524
|
+
this.maxSamples = maxSamples;
|
|
525
|
+
if (!Number.isFinite(maxAgeMs) || maxAgeMs <= 0) {
|
|
526
|
+
throw new Error("Summary maxAgeMs must be greater than zero");
|
|
527
|
+
}
|
|
528
|
+
if (!Number.isInteger(maxSamples) || maxSamples <= 0) {
|
|
529
|
+
throw new Error("Summary maxSamples must be a positive integer");
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
observe(value, labels = {}) {
|
|
533
|
+
const key = this.labelsKey(labels);
|
|
534
|
+
const now = Date.now();
|
|
535
|
+
const observation = this.observations.get(key) ?? {
|
|
536
|
+
count: 0,
|
|
537
|
+
sum: 0,
|
|
538
|
+
samples: []
|
|
539
|
+
};
|
|
540
|
+
observation.count += 1;
|
|
541
|
+
observation.sum += value;
|
|
542
|
+
observation.samples.push({
|
|
543
|
+
value,
|
|
544
|
+
observedAt: now
|
|
545
|
+
});
|
|
546
|
+
this.prune(observation.samples, now);
|
|
547
|
+
this.observations.set(key, observation);
|
|
548
|
+
}
|
|
549
|
+
getQuantile(quantile, labels = {}) {
|
|
550
|
+
const observation = this.observations.get(this.labelsKey(labels));
|
|
551
|
+
if (!observation) return 0;
|
|
552
|
+
this.prune(observation.samples, Date.now());
|
|
553
|
+
const values = observation.samples.map(({ value }) => value);
|
|
554
|
+
if (values.length === 0) return 0;
|
|
555
|
+
const sorted = [
|
|
556
|
+
...values
|
|
557
|
+
].sort((a, b) => a - b);
|
|
558
|
+
const idx = Math.ceil(quantile * sorted.length) - 1;
|
|
559
|
+
return sorted[Math.max(0, idx)];
|
|
560
|
+
}
|
|
561
|
+
getCount(labels = {}) {
|
|
562
|
+
return this.observations.get(this.labelsKey(labels))?.count ?? 0;
|
|
563
|
+
}
|
|
564
|
+
getSum(labels = {}) {
|
|
565
|
+
return this.observations.get(this.labelsKey(labels))?.sum ?? 0;
|
|
566
|
+
}
|
|
567
|
+
getAll() {
|
|
568
|
+
const now = Date.now();
|
|
569
|
+
return Array.from(this.observations.entries()).map(([key, observation]) => {
|
|
570
|
+
this.prune(observation.samples, now);
|
|
571
|
+
const sorted = observation.samples.map(({ value }) => value).sort((a, b) => a - b);
|
|
572
|
+
const quantileValues = {};
|
|
573
|
+
for (const q of this.quantiles) {
|
|
574
|
+
if (sorted.length === 0) {
|
|
575
|
+
quantileValues[String(q)] = 0;
|
|
576
|
+
} else {
|
|
577
|
+
const idx = Math.ceil(q * sorted.length) - 1;
|
|
578
|
+
quantileValues[String(q)] = sorted[Math.max(0, idx)];
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return {
|
|
582
|
+
labels: this.parseKey(key),
|
|
583
|
+
count: observation.count,
|
|
584
|
+
sum: observation.sum,
|
|
585
|
+
quantileValues
|
|
586
|
+
};
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
prune(samples, now) {
|
|
590
|
+
const cutoff = now - this.maxAgeMs;
|
|
591
|
+
let expired = 0;
|
|
592
|
+
while (expired < samples.length && samples[expired].observedAt < cutoff) {
|
|
593
|
+
expired += 1;
|
|
594
|
+
}
|
|
595
|
+
const excess = samples.length - expired - this.maxSamples;
|
|
596
|
+
const removeCount = expired + Math.max(0, excess);
|
|
597
|
+
if (removeCount > 0) samples.splice(0, removeCount);
|
|
598
|
+
}
|
|
599
|
+
labelsKey(labels) {
|
|
600
|
+
return serializeLabels(labels);
|
|
601
|
+
}
|
|
602
|
+
parseKey(key) {
|
|
603
|
+
return deserializeLabels(key);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
var MetricsRegistry = class {
|
|
607
|
+
static {
|
|
608
|
+
__name(this, "MetricsRegistry");
|
|
609
|
+
}
|
|
610
|
+
counters = /* @__PURE__ */ new Map();
|
|
611
|
+
gauges = /* @__PURE__ */ new Map();
|
|
612
|
+
histograms = /* @__PURE__ */ new Map();
|
|
613
|
+
timers = /* @__PURE__ */ new Map();
|
|
614
|
+
summaries = /* @__PURE__ */ new Map();
|
|
615
|
+
counter(name, description = "") {
|
|
616
|
+
let c = this.counters.get(name);
|
|
617
|
+
if (!c) {
|
|
618
|
+
c = new Counter(name, description);
|
|
619
|
+
this.counters.set(name, c);
|
|
620
|
+
}
|
|
621
|
+
return c;
|
|
622
|
+
}
|
|
623
|
+
gauge(name, description = "") {
|
|
624
|
+
let g = this.gauges.get(name);
|
|
625
|
+
if (!g) {
|
|
626
|
+
g = new Gauge(name, description);
|
|
627
|
+
this.gauges.set(name, g);
|
|
628
|
+
}
|
|
629
|
+
return g;
|
|
630
|
+
}
|
|
631
|
+
histogram(name, description = "", buckets) {
|
|
632
|
+
let h = this.histograms.get(name);
|
|
633
|
+
if (!h) {
|
|
634
|
+
h = new Histogram(name, description, buckets);
|
|
635
|
+
this.histograms.set(name, h);
|
|
636
|
+
}
|
|
637
|
+
return h;
|
|
638
|
+
}
|
|
639
|
+
timer(name, description = "") {
|
|
640
|
+
let t = this.timers.get(name);
|
|
641
|
+
if (!t) {
|
|
642
|
+
t = new Timer(name, description);
|
|
643
|
+
this.timers.set(name, t);
|
|
644
|
+
}
|
|
645
|
+
return t;
|
|
646
|
+
}
|
|
647
|
+
summary(name, description = "", quantiles) {
|
|
648
|
+
let s = this.summaries.get(name);
|
|
649
|
+
if (!s) {
|
|
650
|
+
s = new Summary(name, description, quantiles);
|
|
651
|
+
this.summaries.set(name, s);
|
|
652
|
+
}
|
|
653
|
+
return s;
|
|
654
|
+
}
|
|
655
|
+
getCounters() {
|
|
656
|
+
return Array.from(this.counters.values());
|
|
657
|
+
}
|
|
658
|
+
getGauges() {
|
|
659
|
+
return Array.from(this.gauges.values());
|
|
660
|
+
}
|
|
661
|
+
getHistograms() {
|
|
662
|
+
return Array.from(this.histograms.values());
|
|
663
|
+
}
|
|
664
|
+
getTimers() {
|
|
665
|
+
return Array.from(this.timers.values());
|
|
666
|
+
}
|
|
667
|
+
getSummaries() {
|
|
668
|
+
return Array.from(this.summaries.values());
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* 重置所有指标
|
|
672
|
+
*/
|
|
673
|
+
clear() {
|
|
674
|
+
this.counters.clear();
|
|
675
|
+
this.gauges.clear();
|
|
676
|
+
this.histograms.clear();
|
|
677
|
+
this.timers.clear();
|
|
678
|
+
this.summaries.clear();
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
MetricsRegistry = _ts_decorate3([
|
|
682
|
+
(0, import_common3.Injectable)()
|
|
683
|
+
], MetricsRegistry);
|
|
684
|
+
|
|
685
|
+
// src/metrics/metrics.decorator.ts
|
|
686
|
+
function Metrics(name, options) {
|
|
687
|
+
return (_target, propertyKey, descriptor) => {
|
|
688
|
+
const originalMethod = descriptor.value;
|
|
689
|
+
descriptor.value = function(...args) {
|
|
690
|
+
const registry = options?.registry ?? this?.metricsRegistry;
|
|
691
|
+
if (!registry) {
|
|
692
|
+
return originalMethod.apply(this, args);
|
|
693
|
+
}
|
|
694
|
+
const baseLabels = {
|
|
695
|
+
method: String(propertyKey),
|
|
696
|
+
class: this?.constructor?.name ?? "Unknown",
|
|
697
|
+
...options?.labels
|
|
698
|
+
};
|
|
699
|
+
const counter = registry.counter(`${name}_total`, `Total calls to ${String(propertyKey)}`);
|
|
700
|
+
const timer = registry.timer(`${name}_duration_seconds`, `Duration of ${String(propertyKey)}`);
|
|
701
|
+
const trackErrors = options?.trackErrors !== false;
|
|
702
|
+
const trackActive = options?.trackActiveRequests === true;
|
|
703
|
+
counter.increment(baseLabels);
|
|
704
|
+
const stopTimer = timer.startTimer(baseLabels);
|
|
705
|
+
let activeGauge;
|
|
706
|
+
if (trackActive) {
|
|
707
|
+
activeGauge = registry.gauge(`${name}_active_requests`, `Active requests for ${String(propertyKey)}`);
|
|
708
|
+
activeGauge.increment(baseLabels);
|
|
709
|
+
}
|
|
710
|
+
const onFinish = /* @__PURE__ */ __name((isError) => {
|
|
711
|
+
stopTimer();
|
|
712
|
+
if (trackActive && activeGauge) {
|
|
713
|
+
activeGauge.decrement(baseLabels);
|
|
714
|
+
}
|
|
715
|
+
if (isError && trackErrors) {
|
|
716
|
+
const errorCounter = registry.counter(`${name}_errors_total`, `Error calls to ${String(propertyKey)}`);
|
|
717
|
+
errorCounter.increment(baseLabels);
|
|
718
|
+
}
|
|
719
|
+
}, "onFinish");
|
|
720
|
+
try {
|
|
721
|
+
const result = originalMethod.apply(this, args);
|
|
722
|
+
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
723
|
+
return result.then((val) => {
|
|
724
|
+
onFinish(false);
|
|
725
|
+
return val;
|
|
726
|
+
}, (err) => {
|
|
727
|
+
onFinish(true);
|
|
728
|
+
throw err;
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
onFinish(false);
|
|
732
|
+
return result;
|
|
733
|
+
} catch (err) {
|
|
734
|
+
onFinish(true);
|
|
735
|
+
throw err;
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
return descriptor;
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
__name(Metrics, "Metrics");
|
|
742
|
+
|
|
743
|
+
// src/metrics/system-metrics.ts
|
|
744
|
+
var import_common4 = require("@nestjs/common");
|
|
745
|
+
var os = __toESM(require("os"));
|
|
746
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
747
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
748
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
749
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
750
|
+
} else {
|
|
751
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
752
|
+
if (d = decorators[i]) {
|
|
753
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
758
|
+
}
|
|
759
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
760
|
+
function _ts_metadata(metadataKey, metadataValue) {
|
|
761
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
762
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
766
|
+
var SystemMetricsCollector = class {
|
|
767
|
+
static {
|
|
768
|
+
__name(this, "SystemMetricsCollector");
|
|
769
|
+
}
|
|
770
|
+
registry;
|
|
771
|
+
intervalHandle = null;
|
|
772
|
+
options;
|
|
773
|
+
lastCpuUsage = null;
|
|
774
|
+
lastCpuUsageTime = null;
|
|
775
|
+
constructor(registry) {
|
|
776
|
+
this.registry = registry;
|
|
777
|
+
this.options = {
|
|
778
|
+
intervalMs: 15e3,
|
|
779
|
+
enabled: true,
|
|
780
|
+
prefix: ""
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
configure(options) {
|
|
784
|
+
this.options = {
|
|
785
|
+
...this.options,
|
|
786
|
+
...options
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
onModuleInit() {
|
|
790
|
+
if (!this.options.enabled) return;
|
|
791
|
+
this.collect();
|
|
792
|
+
this.intervalHandle = setInterval(() => this.collect(), this.options.intervalMs);
|
|
793
|
+
}
|
|
794
|
+
onModuleDestroy() {
|
|
795
|
+
if (this.intervalHandle) {
|
|
796
|
+
clearInterval(this.intervalHandle);
|
|
797
|
+
this.intervalHandle = null;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
metricName(name) {
|
|
801
|
+
return this.options.prefix ? `${this.options.prefix}_${name}` : name;
|
|
802
|
+
}
|
|
803
|
+
collect() {
|
|
804
|
+
this.collectCpuMetrics();
|
|
805
|
+
this.collectMemoryMetrics();
|
|
806
|
+
this.collectProcessMetrics();
|
|
807
|
+
this.collectUptimeMetrics();
|
|
808
|
+
this.measureEventLoopDelay();
|
|
809
|
+
this.collectHandleMetrics();
|
|
810
|
+
}
|
|
811
|
+
collectCpuMetrics() {
|
|
812
|
+
const cpus2 = os.cpus();
|
|
813
|
+
let totalIdle = 0;
|
|
814
|
+
let totalTick = 0;
|
|
815
|
+
for (const cpu of cpus2) {
|
|
816
|
+
const times = cpu.times;
|
|
817
|
+
totalIdle += times.idle;
|
|
818
|
+
totalTick += times.user + times.nice + times.sys + times.irq + times.idle;
|
|
819
|
+
}
|
|
820
|
+
const cpuUsage = totalTick > 0 ? 1 - totalIdle / totalTick : 0;
|
|
821
|
+
this.registry.gauge(this.metricName("system_cpu_usage"), "System CPU usage ratio").set(cpuUsage);
|
|
822
|
+
this.registry.gauge(this.metricName("system_cpu_count"), "Number of CPUs").set(cpus2.length);
|
|
823
|
+
const currentCpuUsage = process.cpuUsage();
|
|
824
|
+
const now = process.hrtime.bigint();
|
|
825
|
+
if (this.lastCpuUsage && this.lastCpuUsageTime) {
|
|
826
|
+
const elapsedMicros = Number(now - this.lastCpuUsageTime) / 1e3;
|
|
827
|
+
if (elapsedMicros > 0) {
|
|
828
|
+
const userDiff = currentCpuUsage.user - this.lastCpuUsage.user;
|
|
829
|
+
const systemDiff = currentCpuUsage.system - this.lastCpuUsage.system;
|
|
830
|
+
const processCpuUsage = (userDiff + systemDiff) / elapsedMicros;
|
|
831
|
+
this.registry.gauge(this.metricName("process_cpu_usage"), "Process CPU usage ratio").set(Math.min(1, processCpuUsage));
|
|
832
|
+
this.registry.gauge(this.metricName("process_cpu_user_seconds_total"), "Process CPU user time total").set(currentCpuUsage.user / 1e6);
|
|
833
|
+
this.registry.gauge(this.metricName("process_cpu_system_seconds_total"), "Process CPU system time total").set(currentCpuUsage.system / 1e6);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
this.lastCpuUsage = currentCpuUsage;
|
|
837
|
+
this.lastCpuUsageTime = now;
|
|
838
|
+
}
|
|
839
|
+
collectMemoryMetrics() {
|
|
840
|
+
const totalMem = os.totalmem();
|
|
841
|
+
const freeMem = os.freemem();
|
|
842
|
+
this.registry.gauge(this.metricName("system_memory_total_bytes"), "Total system memory").set(totalMem);
|
|
843
|
+
this.registry.gauge(this.metricName("system_memory_free_bytes"), "Free system memory").set(freeMem);
|
|
844
|
+
this.registry.gauge(this.metricName("system_memory_used_bytes"), "Used system memory").set(totalMem - freeMem);
|
|
845
|
+
}
|
|
846
|
+
collectProcessMetrics() {
|
|
847
|
+
const memUsage = process.memoryUsage();
|
|
848
|
+
this.registry.gauge(this.metricName("process_memory_rss_bytes"), "Process RSS").set(memUsage.rss);
|
|
849
|
+
this.registry.gauge(this.metricName("process_memory_heap_total_bytes"), "Process heap total").set(memUsage.heapTotal);
|
|
850
|
+
this.registry.gauge(this.metricName("process_memory_heap_used_bytes"), "Process heap used").set(memUsage.heapUsed);
|
|
851
|
+
this.registry.gauge(this.metricName("process_memory_external_bytes"), "Process external memory").set(memUsage.external);
|
|
852
|
+
if (memUsage.arrayBuffers !== void 0) {
|
|
853
|
+
this.registry.gauge(this.metricName("process_memory_array_buffers_bytes"), "Process ArrayBuffers memory").set(memUsage.arrayBuffers);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
collectUptimeMetrics() {
|
|
857
|
+
const processUptime = process.uptime();
|
|
858
|
+
this.registry.gauge(this.metricName("process_uptime_seconds"), "Process uptime").set(processUptime);
|
|
859
|
+
let systemUptime = 0;
|
|
860
|
+
try {
|
|
861
|
+
systemUptime = os.uptime();
|
|
862
|
+
} catch {
|
|
863
|
+
systemUptime = 0;
|
|
864
|
+
}
|
|
865
|
+
this.registry.gauge(this.metricName("system_uptime_seconds"), "System uptime").set(systemUptime);
|
|
866
|
+
this.registry.gauge(this.metricName("process_start_time_seconds"), "Process start time (Unix epoch)").set(Math.floor(Date.now() / 1e3 - processUptime));
|
|
867
|
+
}
|
|
868
|
+
measureEventLoopDelay() {
|
|
869
|
+
const start = process.hrtime.bigint();
|
|
870
|
+
setImmediate(() => {
|
|
871
|
+
const delay = Number(process.hrtime.bigint() - start) / 1e6;
|
|
872
|
+
this.registry.gauge(this.metricName("process_event_loop_delay_ms"), "Event loop delay").set(delay);
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
collectHandleMetrics() {
|
|
876
|
+
const activeHandles = process._getActiveHandles?.()?.length;
|
|
877
|
+
const activeRequests = process._getActiveRequests?.()?.length;
|
|
878
|
+
if (typeof activeHandles === "number") {
|
|
879
|
+
this.registry.gauge(this.metricName("process_active_handles"), "Number of active handles").set(activeHandles);
|
|
880
|
+
}
|
|
881
|
+
if (typeof activeRequests === "number") {
|
|
882
|
+
this.registry.gauge(this.metricName("process_active_requests"), "Number of active requests").set(activeRequests);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
SystemMetricsCollector = _ts_decorate4([
|
|
887
|
+
(0, import_common4.Injectable)(),
|
|
888
|
+
_ts_metadata("design:type", Function),
|
|
889
|
+
_ts_metadata("design:paramtypes", [
|
|
890
|
+
typeof MetricsRegistry === "undefined" ? Object : MetricsRegistry
|
|
891
|
+
])
|
|
892
|
+
], SystemMetricsCollector);
|
|
893
|
+
|
|
894
|
+
// src/metrics/prometheus-exporter.ts
|
|
895
|
+
var import_common5 = require("@nestjs/common");
|
|
896
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
897
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
898
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
899
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
900
|
+
} else {
|
|
901
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
902
|
+
if (d = decorators[i]) {
|
|
903
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
908
|
+
}
|
|
909
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
910
|
+
function _ts_metadata2(metadataKey, metadataValue) {
|
|
911
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
912
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
916
|
+
function _ts_param(paramIndex, decorator) {
|
|
917
|
+
return function(target, key) {
|
|
918
|
+
decorator(target, key, paramIndex);
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
__name(_ts_param, "_ts_param");
|
|
922
|
+
function formatLabels(labels) {
|
|
923
|
+
const entries = Object.entries(labels);
|
|
924
|
+
if (entries.length === 0) return "";
|
|
925
|
+
const pairs = entries.map(([key, value]) => `${key}="${escapeLabelValue(value)}"`);
|
|
926
|
+
return `{${pairs.join(",")}}`;
|
|
927
|
+
}
|
|
928
|
+
__name(formatLabels, "formatLabels");
|
|
929
|
+
function escapeHelp(text) {
|
|
930
|
+
return text.replace(/\\/g, "\\\\").replace(/\n/g, "\\n");
|
|
931
|
+
}
|
|
932
|
+
__name(escapeHelp, "escapeHelp");
|
|
933
|
+
function escapeLabelValue(value) {
|
|
934
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
|
|
935
|
+
}
|
|
936
|
+
__name(escapeLabelValue, "escapeLabelValue");
|
|
937
|
+
function renderPrometheusMetrics(registry) {
|
|
938
|
+
const lines = [];
|
|
939
|
+
for (const counter of registry.getCounters()) {
|
|
940
|
+
lines.push(`# HELP ${counter.name} ${escapeHelp(counter.description)}`);
|
|
941
|
+
lines.push(`# TYPE ${counter.name} counter`);
|
|
942
|
+
for (const { labels, value } of counter.getAll()) {
|
|
943
|
+
lines.push(`${counter.name}${formatLabels(labels)} ${value}`);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
for (const gauge of registry.getGauges()) {
|
|
947
|
+
lines.push(`# HELP ${gauge.name} ${escapeHelp(gauge.description)}`);
|
|
948
|
+
lines.push(`# TYPE ${gauge.name} gauge`);
|
|
949
|
+
for (const { labels, value } of gauge.getAll()) {
|
|
950
|
+
lines.push(`${gauge.name}${formatLabels(labels)} ${value}`);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
for (const histogram of registry.getHistograms()) {
|
|
954
|
+
lines.push(`# HELP ${histogram.name} ${escapeHelp(histogram.description)}`);
|
|
955
|
+
lines.push(`# TYPE ${histogram.name} histogram`);
|
|
956
|
+
for (const { labels, count, sum, bucketCounts } of histogram.getAll()) {
|
|
957
|
+
for (const [le, value] of Object.entries(bucketCounts)) {
|
|
958
|
+
lines.push(`${histogram.name}_bucket${formatLabels({
|
|
959
|
+
...labels,
|
|
960
|
+
le
|
|
961
|
+
})} ${value}`);
|
|
962
|
+
}
|
|
963
|
+
lines.push(`${histogram.name}_count${formatLabels(labels)} ${count}`);
|
|
964
|
+
lines.push(`${histogram.name}_sum${formatLabels(labels)} ${sum}`);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
for (const timer of registry.getTimers()) {
|
|
968
|
+
const histogram = timer.getHistogram();
|
|
969
|
+
lines.push(`# HELP ${timer.name} ${escapeHelp(timer.description)}`);
|
|
970
|
+
lines.push(`# TYPE ${timer.name} histogram`);
|
|
971
|
+
for (const { labels, count, sum, bucketCounts } of histogram.getAll()) {
|
|
972
|
+
for (const [le, value] of Object.entries(bucketCounts)) {
|
|
973
|
+
lines.push(`${timer.name}_bucket${formatLabels({
|
|
974
|
+
...labels,
|
|
975
|
+
le
|
|
976
|
+
})} ${value}`);
|
|
977
|
+
}
|
|
978
|
+
lines.push(`${timer.name}_count${formatLabels(labels)} ${count}`);
|
|
979
|
+
lines.push(`${timer.name}_sum${formatLabels(labels)} ${sum}`);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
for (const summary of registry.getSummaries()) {
|
|
983
|
+
lines.push(`# HELP ${summary.name} ${escapeHelp(summary.description)}`);
|
|
984
|
+
lines.push(`# TYPE ${summary.name} summary`);
|
|
985
|
+
for (const { labels, count, sum, quantileValues } of summary.getAll()) {
|
|
986
|
+
for (const [quantile, value] of Object.entries(quantileValues)) {
|
|
987
|
+
lines.push(`${summary.name}${formatLabels({
|
|
988
|
+
...labels,
|
|
989
|
+
quantile
|
|
990
|
+
})} ${value}`);
|
|
991
|
+
}
|
|
992
|
+
lines.push(`${summary.name}_count${formatLabels(labels)} ${count}`);
|
|
993
|
+
lines.push(`${summary.name}_sum${formatLabels(labels)} ${sum}`);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
return `${lines.join("\n")}
|
|
997
|
+
`;
|
|
998
|
+
}
|
|
999
|
+
__name(renderPrometheusMetrics, "renderPrometheusMetrics");
|
|
1000
|
+
var PrometheusExporter = class {
|
|
1001
|
+
static {
|
|
1002
|
+
__name(this, "PrometheusExporter");
|
|
1003
|
+
}
|
|
1004
|
+
registry;
|
|
1005
|
+
constructor(registry) {
|
|
1006
|
+
this.registry = registry;
|
|
1007
|
+
}
|
|
1008
|
+
getMetrics() {
|
|
1009
|
+
return renderPrometheusMetrics(this.registry);
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
_ts_decorate5([
|
|
1013
|
+
(0, import_common5.Get)(),
|
|
1014
|
+
(0, import_common5.Header)("Content-Type", "text/plain; version=0.0.4; charset=utf-8"),
|
|
1015
|
+
_ts_metadata2("design:type", Function),
|
|
1016
|
+
_ts_metadata2("design:paramtypes", []),
|
|
1017
|
+
_ts_metadata2("design:returntype", String)
|
|
1018
|
+
], PrometheusExporter.prototype, "getMetrics", null);
|
|
1019
|
+
PrometheusExporter = _ts_decorate5([
|
|
1020
|
+
(0, import_common5.Controller)("metrics"),
|
|
1021
|
+
_ts_param(0, (0, import_common5.Inject)(MetricsRegistry)),
|
|
1022
|
+
_ts_metadata2("design:type", Function),
|
|
1023
|
+
_ts_metadata2("design:paramtypes", [
|
|
1024
|
+
typeof MetricsRegistry === "undefined" ? Object : MetricsRegistry
|
|
1025
|
+
])
|
|
1026
|
+
], PrometheusExporter);
|
|
1027
|
+
|
|
1028
|
+
// src/monitoring.module.ts
|
|
1029
|
+
var import_common9 = require("@nestjs/common");
|
|
1030
|
+
|
|
1031
|
+
// src/health.controller.ts
|
|
1032
|
+
var import_common6 = require("@nestjs/common");
|
|
1033
|
+
|
|
1034
|
+
// src/process-uptime.ts
|
|
1035
|
+
function getProcessUptime(startedAtMs, nowMs = Date.now()) {
|
|
1036
|
+
const uptimeMs = Math.max(0, nowMs - startedAtMs);
|
|
1037
|
+
return {
|
|
1038
|
+
uptimeMs,
|
|
1039
|
+
uptimeSeconds: Math.floor(uptimeMs / 1e3)
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
__name(getProcessUptime, "getProcessUptime");
|
|
1043
|
+
|
|
1044
|
+
// src/health.controller.ts
|
|
1045
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
1046
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1047
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1048
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1049
|
+
} else {
|
|
1050
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
1051
|
+
if (d = decorators[i]) {
|
|
1052
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1057
|
+
}
|
|
1058
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
1059
|
+
function _ts_metadata3(metadataKey, metadataValue) {
|
|
1060
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
1061
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
1065
|
+
function _ts_param2(paramIndex, decorator) {
|
|
1066
|
+
return function(target, key) {
|
|
1067
|
+
decorator(target, key, paramIndex);
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
__name(_ts_param2, "_ts_param");
|
|
1071
|
+
var Public = /* @__PURE__ */ __name(() => (0, import_common6.SetMetadata)("zucker:auth:isPublic", true), "Public");
|
|
1072
|
+
var HEALTH_OPTIONS = /* @__PURE__ */ Symbol("HEALTH_OPTIONS");
|
|
1073
|
+
var HealthController = class {
|
|
1074
|
+
static {
|
|
1075
|
+
__name(this, "HealthController");
|
|
1076
|
+
}
|
|
1077
|
+
healthCheckService;
|
|
1078
|
+
startedAtMs = Date.now();
|
|
1079
|
+
constructor(healthCheckService) {
|
|
1080
|
+
this.healthCheckService = healthCheckService;
|
|
1081
|
+
}
|
|
1082
|
+
async check(res) {
|
|
1083
|
+
const result = await this.healthCheckService.checkAll();
|
|
1084
|
+
const statusCode = result.status === HealthStatus.DOWN ? 503 : 200;
|
|
1085
|
+
res.status(statusCode).json({
|
|
1086
|
+
status: result.status === HealthStatus.UP ? "up" : result.status === HealthStatus.DEGRADED ? "degraded" : "down",
|
|
1087
|
+
checks: this.formatChecks(result.checks),
|
|
1088
|
+
...getProcessUptime(this.startedAtMs),
|
|
1089
|
+
timestamp: result.timestamp.toISOString()
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* K8s liveness 探针 — 仅检查进程是否存活
|
|
1094
|
+
*/
|
|
1095
|
+
live(res) {
|
|
1096
|
+
res.status(200).json({
|
|
1097
|
+
status: "up",
|
|
1098
|
+
...getProcessUptime(this.startedAtMs),
|
|
1099
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* K8s readiness 探针 — 检查所有依赖是否就绪
|
|
1104
|
+
*/
|
|
1105
|
+
async ready(res) {
|
|
1106
|
+
const result = await this.healthCheckService.checkAll();
|
|
1107
|
+
const isReady = result.status !== HealthStatus.DOWN;
|
|
1108
|
+
const statusCode = isReady ? 200 : 503;
|
|
1109
|
+
res.status(statusCode).json({
|
|
1110
|
+
status: isReady ? "up" : "down",
|
|
1111
|
+
checks: this.formatChecks(result.checks),
|
|
1112
|
+
...getProcessUptime(this.startedAtMs),
|
|
1113
|
+
timestamp: result.timestamp.toISOString()
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
formatChecks(checks) {
|
|
1117
|
+
const formatted = {};
|
|
1118
|
+
for (const check of checks) {
|
|
1119
|
+
formatted[check.name] = {
|
|
1120
|
+
status: check.status === HealthStatus.UP ? "up" : check.status === HealthStatus.DEGRADED ? "degraded" : "down",
|
|
1121
|
+
details: check.details
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
return formatted;
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
_ts_decorate6([
|
|
1128
|
+
(0, import_common6.Get)(),
|
|
1129
|
+
_ts_param2(0, (0, import_common6.Res)()),
|
|
1130
|
+
_ts_metadata3("design:type", Function),
|
|
1131
|
+
_ts_metadata3("design:paramtypes", [
|
|
1132
|
+
Object
|
|
1133
|
+
]),
|
|
1134
|
+
_ts_metadata3("design:returntype", Promise)
|
|
1135
|
+
], HealthController.prototype, "check", null);
|
|
1136
|
+
_ts_decorate6([
|
|
1137
|
+
(0, import_common6.Get)("live"),
|
|
1138
|
+
_ts_param2(0, (0, import_common6.Res)()),
|
|
1139
|
+
_ts_metadata3("design:type", Function),
|
|
1140
|
+
_ts_metadata3("design:paramtypes", [
|
|
1141
|
+
Object
|
|
1142
|
+
]),
|
|
1143
|
+
_ts_metadata3("design:returntype", void 0)
|
|
1144
|
+
], HealthController.prototype, "live", null);
|
|
1145
|
+
_ts_decorate6([
|
|
1146
|
+
(0, import_common6.Get)("ready"),
|
|
1147
|
+
_ts_param2(0, (0, import_common6.Res)()),
|
|
1148
|
+
_ts_metadata3("design:type", Function),
|
|
1149
|
+
_ts_metadata3("design:paramtypes", [
|
|
1150
|
+
Object
|
|
1151
|
+
]),
|
|
1152
|
+
_ts_metadata3("design:returntype", Promise)
|
|
1153
|
+
], HealthController.prototype, "ready", null);
|
|
1154
|
+
HealthController = _ts_decorate6([
|
|
1155
|
+
(0, import_common6.Controller)("health"),
|
|
1156
|
+
Public(),
|
|
1157
|
+
_ts_metadata3("design:type", Function),
|
|
1158
|
+
_ts_metadata3("design:paramtypes", [
|
|
1159
|
+
typeof HealthCheckService === "undefined" ? Object : HealthCheckService
|
|
1160
|
+
])
|
|
1161
|
+
], HealthController);
|
|
1162
|
+
|
|
1163
|
+
// src/alert/alert-manager.service.ts
|
|
1164
|
+
var import_common7 = require("@nestjs/common");
|
|
1165
|
+
var import_crypto = require("crypto");
|
|
1166
|
+
var import_event_emitter = require("@nestjs/event-emitter");
|
|
1167
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
1168
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1169
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1170
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1171
|
+
} else {
|
|
1172
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
1173
|
+
if (d = decorators[i]) {
|
|
1174
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1179
|
+
}
|
|
1180
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
1181
|
+
function _ts_metadata4(metadataKey, metadataValue) {
|
|
1182
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
1183
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
1187
|
+
function _ts_param3(paramIndex, decorator) {
|
|
1188
|
+
return function(target, key) {
|
|
1189
|
+
decorator(target, key, paramIndex);
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
__name(_ts_param3, "_ts_param");
|
|
1193
|
+
function nextAlertId() {
|
|
1194
|
+
return `alert-${Date.now()}-${(0, import_crypto.randomUUID)().slice(0, 8)}`;
|
|
1195
|
+
}
|
|
1196
|
+
__name(nextAlertId, "nextAlertId");
|
|
1197
|
+
var AlertManagerService = class _AlertManagerService {
|
|
1198
|
+
static {
|
|
1199
|
+
__name(this, "AlertManagerService");
|
|
1200
|
+
}
|
|
1201
|
+
eventEmitter;
|
|
1202
|
+
db;
|
|
1203
|
+
logger = new import_common7.Logger(_AlertManagerService.name);
|
|
1204
|
+
/** 已注册的告警规则 */
|
|
1205
|
+
rules = /* @__PURE__ */ new Map();
|
|
1206
|
+
/** 所有告警记录(含历史) */
|
|
1207
|
+
alerts = /* @__PURE__ */ new Map();
|
|
1208
|
+
/** 每条规则的持续违规状态 */
|
|
1209
|
+
violations = /* @__PURE__ */ new Map();
|
|
1210
|
+
/** 活跃告警的 ruleId 索引(非 RESOLVED 状态的告警) */
|
|
1211
|
+
activeRuleIds = /* @__PURE__ */ new Set();
|
|
1212
|
+
constructor(eventEmitter, db) {
|
|
1213
|
+
this.eventEmitter = eventEmitter;
|
|
1214
|
+
this.db = db;
|
|
1215
|
+
}
|
|
1216
|
+
async onModuleInit() {
|
|
1217
|
+
if (!this.db) return;
|
|
1218
|
+
try {
|
|
1219
|
+
const rules = await this.db.model("alertRules").findMany({});
|
|
1220
|
+
for (const rule of rules) {
|
|
1221
|
+
this.rules.set(rule.id, rule);
|
|
1222
|
+
}
|
|
1223
|
+
if (rules.length > 0) {
|
|
1224
|
+
this.logger.log(`Loaded ${rules.length} alert rules from database`);
|
|
1225
|
+
}
|
|
1226
|
+
} catch {
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
// ─── 规则管理 ───────────────────────────────────────
|
|
1230
|
+
registerRule(rule) {
|
|
1231
|
+
this.rules.set(rule.id, {
|
|
1232
|
+
...rule
|
|
1233
|
+
});
|
|
1234
|
+
if (this.db) {
|
|
1235
|
+
this.db.model("alertRules").update({
|
|
1236
|
+
where: {
|
|
1237
|
+
id: rule.id
|
|
1238
|
+
},
|
|
1239
|
+
data: {
|
|
1240
|
+
...rule
|
|
1241
|
+
}
|
|
1242
|
+
}).catch(() => {
|
|
1243
|
+
this.db.model("alertRules").create({
|
|
1244
|
+
data: {
|
|
1245
|
+
...rule
|
|
1246
|
+
}
|
|
1247
|
+
}).catch((dbErr) => {
|
|
1248
|
+
this.logger.warn(`Failed to persist alert rule ${rule.id} to database: ${dbErr instanceof Error ? dbErr.message : String(dbErr)}`);
|
|
1249
|
+
});
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
this.logger.log(`Alert rule registered: ${rule.name} (${rule.id})`);
|
|
1253
|
+
}
|
|
1254
|
+
removeRule(ruleId) {
|
|
1255
|
+
const deleted = this.rules.delete(ruleId);
|
|
1256
|
+
if (deleted) {
|
|
1257
|
+
this.violations.delete(ruleId);
|
|
1258
|
+
this.logger.log(`Alert rule removed: ${ruleId}`);
|
|
1259
|
+
}
|
|
1260
|
+
return deleted;
|
|
1261
|
+
}
|
|
1262
|
+
getRules() {
|
|
1263
|
+
return Array.from(this.rules.values());
|
|
1264
|
+
}
|
|
1265
|
+
getRule(ruleId) {
|
|
1266
|
+
return this.rules.get(ruleId);
|
|
1267
|
+
}
|
|
1268
|
+
// ─── 告警评估 ───────────────────────────────────────
|
|
1269
|
+
/**
|
|
1270
|
+
* 对一组指标快照评估所有已启用规则。
|
|
1271
|
+
* 应由调度器(如 Cron / Interval)定期调用。
|
|
1272
|
+
*/
|
|
1273
|
+
evaluate(metrics) {
|
|
1274
|
+
const triggered = [];
|
|
1275
|
+
const now = Date.now();
|
|
1276
|
+
for (const rule of this.rules.values()) {
|
|
1277
|
+
if (!rule.enabled) continue;
|
|
1278
|
+
const value = metrics[rule.metric];
|
|
1279
|
+
if (value === void 0) continue;
|
|
1280
|
+
const violated = this.checkCondition(value, rule.condition, rule.threshold);
|
|
1281
|
+
if (violated) {
|
|
1282
|
+
const state = this.violations.get(rule.id);
|
|
1283
|
+
if (state) {
|
|
1284
|
+
state.count++;
|
|
1285
|
+
state.lastValue = value;
|
|
1286
|
+
} else {
|
|
1287
|
+
this.violations.set(rule.id, {
|
|
1288
|
+
startedAt: now,
|
|
1289
|
+
count: 1,
|
|
1290
|
+
lastValue: value
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
const current = this.violations.get(rule.id);
|
|
1294
|
+
const elapsedSec = (now - current.startedAt) / 1e3;
|
|
1295
|
+
if (elapsedSec >= rule.duration && !this.hasActiveAlertForRule(rule.id)) {
|
|
1296
|
+
const record = this.createAlert(rule, value);
|
|
1297
|
+
triggered.push(record);
|
|
1298
|
+
}
|
|
1299
|
+
} else {
|
|
1300
|
+
this.violations.delete(rule.id);
|
|
1301
|
+
this.autoResolveForRule(rule.id);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
return triggered;
|
|
1305
|
+
}
|
|
1306
|
+
// ─── 告警查询 ───────────────────────────────────────
|
|
1307
|
+
getAlerts() {
|
|
1308
|
+
return Array.from(this.alerts.values());
|
|
1309
|
+
}
|
|
1310
|
+
getActiveAlerts() {
|
|
1311
|
+
return Array.from(this.alerts.values()).filter((a) => a.status === "ACTIVE");
|
|
1312
|
+
}
|
|
1313
|
+
getAlert(alertId) {
|
|
1314
|
+
return this.alerts.get(alertId);
|
|
1315
|
+
}
|
|
1316
|
+
// ─── 告警操作 ───────────────────────────────────────
|
|
1317
|
+
acknowledgeAlert(alertId, userId) {
|
|
1318
|
+
const alert = this.alerts.get(alertId);
|
|
1319
|
+
if (!alert || alert.status !== "ACTIVE") return void 0;
|
|
1320
|
+
alert.status = "ACKNOWLEDGED";
|
|
1321
|
+
alert.acknowledgedAt = Date.now();
|
|
1322
|
+
alert.acknowledgedBy = userId;
|
|
1323
|
+
this.eventEmitter?.emit("alert.acknowledged", {
|
|
1324
|
+
...alert
|
|
1325
|
+
});
|
|
1326
|
+
this.logger.log(`Alert acknowledged: ${alertId} by ${userId}`);
|
|
1327
|
+
return {
|
|
1328
|
+
...alert
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
resolveAlert(alertId, userId) {
|
|
1332
|
+
const alert = this.alerts.get(alertId);
|
|
1333
|
+
if (!alert || alert.status === "RESOLVED") return void 0;
|
|
1334
|
+
alert.status = "RESOLVED";
|
|
1335
|
+
alert.resolvedAt = Date.now();
|
|
1336
|
+
alert.resolvedBy = userId;
|
|
1337
|
+
this.violations.delete(alert.ruleId);
|
|
1338
|
+
if (!Array.from(this.alerts.values()).some((a) => a.ruleId === alert.ruleId && a.id !== alertId && a.status !== "RESOLVED")) {
|
|
1339
|
+
this.activeRuleIds.delete(alert.ruleId);
|
|
1340
|
+
}
|
|
1341
|
+
this.eventEmitter?.emit("alert.resolved", {
|
|
1342
|
+
...alert
|
|
1343
|
+
});
|
|
1344
|
+
this.logger.log(`Alert resolved: ${alertId} by ${userId}`);
|
|
1345
|
+
return {
|
|
1346
|
+
...alert
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
// ─── 内部方法 ───────────────────────────────────────
|
|
1350
|
+
checkCondition(value, condition, threshold) {
|
|
1351
|
+
switch (condition) {
|
|
1352
|
+
case ">":
|
|
1353
|
+
return value > threshold;
|
|
1354
|
+
case ">=":
|
|
1355
|
+
return value >= threshold;
|
|
1356
|
+
case "<":
|
|
1357
|
+
return value < threshold;
|
|
1358
|
+
case "<=":
|
|
1359
|
+
return value <= threshold;
|
|
1360
|
+
case "==":
|
|
1361
|
+
return value === threshold;
|
|
1362
|
+
case "!=":
|
|
1363
|
+
return value !== threshold;
|
|
1364
|
+
default:
|
|
1365
|
+
return false;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
hasActiveAlertForRule(ruleId) {
|
|
1369
|
+
return this.activeRuleIds.has(ruleId);
|
|
1370
|
+
}
|
|
1371
|
+
createAlert(rule, value) {
|
|
1372
|
+
const record = {
|
|
1373
|
+
id: nextAlertId(),
|
|
1374
|
+
ruleId: rule.id,
|
|
1375
|
+
ruleName: rule.name,
|
|
1376
|
+
metric: rule.metric,
|
|
1377
|
+
value,
|
|
1378
|
+
threshold: rule.threshold,
|
|
1379
|
+
severity: rule.severity,
|
|
1380
|
+
status: "ACTIVE",
|
|
1381
|
+
message: `${rule.metric} ${rule.condition} ${rule.threshold} (current: ${value})`,
|
|
1382
|
+
triggeredAt: Date.now()
|
|
1383
|
+
};
|
|
1384
|
+
this.alerts.set(record.id, record);
|
|
1385
|
+
this.activeRuleIds.add(rule.id);
|
|
1386
|
+
this.eventEmitter?.emit("alert.triggered", {
|
|
1387
|
+
...record
|
|
1388
|
+
});
|
|
1389
|
+
this.logger.warn(`Alert triggered: [${record.severity}] ${record.message}`);
|
|
1390
|
+
return {
|
|
1391
|
+
...record
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
autoResolveForRule(ruleId) {
|
|
1395
|
+
for (const alert of this.alerts.values()) {
|
|
1396
|
+
if (alert.ruleId === ruleId && alert.status !== "RESOLVED") {
|
|
1397
|
+
alert.status = "RESOLVED";
|
|
1398
|
+
alert.resolvedAt = Date.now();
|
|
1399
|
+
alert.resolvedBy = "system";
|
|
1400
|
+
this.eventEmitter?.emit("alert.resolved", {
|
|
1401
|
+
...alert
|
|
1402
|
+
});
|
|
1403
|
+
this.logger.log(`Alert auto-resolved: ${alert.id} (metric recovered)`);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
if (!Array.from(this.alerts.values()).some((a) => a.ruleId === ruleId && a.status !== "RESOLVED")) {
|
|
1407
|
+
this.activeRuleIds.delete(ruleId);
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
AlertManagerService = _ts_decorate7([
|
|
1412
|
+
(0, import_common7.Injectable)(),
|
|
1413
|
+
_ts_param3(0, (0, import_common7.Optional)()),
|
|
1414
|
+
_ts_param3(1, (0, import_common7.Optional)()),
|
|
1415
|
+
_ts_param3(1, (0, import_common7.Inject)("DATABASE_ADAPTER")),
|
|
1416
|
+
_ts_metadata4("design:type", Function),
|
|
1417
|
+
_ts_metadata4("design:paramtypes", [
|
|
1418
|
+
typeof import_event_emitter.EventEmitter2 === "undefined" ? Object : import_event_emitter.EventEmitter2,
|
|
1419
|
+
Object
|
|
1420
|
+
])
|
|
1421
|
+
], AlertManagerService);
|
|
1422
|
+
|
|
1423
|
+
// src/alert/alert.controller.ts
|
|
1424
|
+
var import_common8 = require("@nestjs/common");
|
|
1425
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
1426
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1427
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1428
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1429
|
+
} else {
|
|
1430
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
1431
|
+
if (d = decorators[i]) {
|
|
1432
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1437
|
+
}
|
|
1438
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
1439
|
+
function _ts_metadata5(metadataKey, metadataValue) {
|
|
1440
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
1441
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
1445
|
+
function _ts_param4(paramIndex, decorator) {
|
|
1446
|
+
return function(target, key) {
|
|
1447
|
+
decorator(target, key, paramIndex);
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
__name(_ts_param4, "_ts_param");
|
|
1451
|
+
var Permissions = /* @__PURE__ */ __name(() => (0, import_common8.SetMetadata)("zucker:auth:permissions", []), "Permissions");
|
|
1452
|
+
var AlertController = class {
|
|
1453
|
+
static {
|
|
1454
|
+
__name(this, "AlertController");
|
|
1455
|
+
}
|
|
1456
|
+
alertManager;
|
|
1457
|
+
constructor(alertManager) {
|
|
1458
|
+
this.alertManager = alertManager;
|
|
1459
|
+
}
|
|
1460
|
+
// ─── 告警列表 ───────────────────────────────────────
|
|
1461
|
+
getAlerts() {
|
|
1462
|
+
return this.alertManager.getAlerts();
|
|
1463
|
+
}
|
|
1464
|
+
// ─── 规则管理 ───────────────────────────────────────
|
|
1465
|
+
getRules() {
|
|
1466
|
+
return this.alertManager.getRules();
|
|
1467
|
+
}
|
|
1468
|
+
createRule(body) {
|
|
1469
|
+
if (!body.id || !body.name || !body.metric || body.threshold === void 0) {
|
|
1470
|
+
throw new import_common8.BadRequestException("Missing required fields: id, name, metric, threshold");
|
|
1471
|
+
}
|
|
1472
|
+
const rule = {
|
|
1473
|
+
id: body.id,
|
|
1474
|
+
name: body.name,
|
|
1475
|
+
metric: body.metric,
|
|
1476
|
+
condition: body.condition ?? ">",
|
|
1477
|
+
threshold: body.threshold,
|
|
1478
|
+
duration: body.duration ?? 0,
|
|
1479
|
+
severity: body.severity ?? "MEDIUM",
|
|
1480
|
+
enabled: body.enabled !== false,
|
|
1481
|
+
notifyChannels: body.notifyChannels
|
|
1482
|
+
};
|
|
1483
|
+
this.alertManager.registerRule(rule);
|
|
1484
|
+
return rule;
|
|
1485
|
+
}
|
|
1486
|
+
deleteRule(id) {
|
|
1487
|
+
const removed = this.alertManager.removeRule(id);
|
|
1488
|
+
if (!removed) {
|
|
1489
|
+
throw new import_common8.NotFoundException(`Rule ${id} not found`);
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
// ─── 告警操作 ───────────────────────────────────────
|
|
1493
|
+
acknowledgeAlert(id, userId) {
|
|
1494
|
+
if (!userId) {
|
|
1495
|
+
throw new import_common8.BadRequestException("userId is required");
|
|
1496
|
+
}
|
|
1497
|
+
const result = this.alertManager.acknowledgeAlert(id, userId);
|
|
1498
|
+
if (!result) {
|
|
1499
|
+
throw new import_common8.NotFoundException(`Alert ${id} not found or not in ACTIVE status`);
|
|
1500
|
+
}
|
|
1501
|
+
return result;
|
|
1502
|
+
}
|
|
1503
|
+
resolveAlert(id, userId) {
|
|
1504
|
+
if (!userId) {
|
|
1505
|
+
throw new import_common8.BadRequestException("userId is required");
|
|
1506
|
+
}
|
|
1507
|
+
const result = this.alertManager.resolveAlert(id, userId);
|
|
1508
|
+
if (!result) {
|
|
1509
|
+
throw new import_common8.NotFoundException(`Alert ${id} not found or already resolved`);
|
|
1510
|
+
}
|
|
1511
|
+
return result;
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1514
|
+
_ts_decorate8([
|
|
1515
|
+
(0, import_common8.Get)(),
|
|
1516
|
+
_ts_metadata5("design:type", Function),
|
|
1517
|
+
_ts_metadata5("design:paramtypes", []),
|
|
1518
|
+
_ts_metadata5("design:returntype", void 0)
|
|
1519
|
+
], AlertController.prototype, "getAlerts", null);
|
|
1520
|
+
_ts_decorate8([
|
|
1521
|
+
(0, import_common8.Get)("rules"),
|
|
1522
|
+
_ts_metadata5("design:type", Function),
|
|
1523
|
+
_ts_metadata5("design:paramtypes", []),
|
|
1524
|
+
_ts_metadata5("design:returntype", void 0)
|
|
1525
|
+
], AlertController.prototype, "getRules", null);
|
|
1526
|
+
_ts_decorate8([
|
|
1527
|
+
(0, import_common8.Post)("rules"),
|
|
1528
|
+
(0, import_common8.HttpCode)(import_common8.HttpStatus.CREATED),
|
|
1529
|
+
_ts_param4(0, (0, import_common8.Body)()),
|
|
1530
|
+
_ts_metadata5("design:type", Function),
|
|
1531
|
+
_ts_metadata5("design:paramtypes", [
|
|
1532
|
+
typeof AlertRule === "undefined" ? Object : AlertRule
|
|
1533
|
+
]),
|
|
1534
|
+
_ts_metadata5("design:returntype", void 0)
|
|
1535
|
+
], AlertController.prototype, "createRule", null);
|
|
1536
|
+
_ts_decorate8([
|
|
1537
|
+
(0, import_common8.Delete)("rules/:id"),
|
|
1538
|
+
(0, import_common8.HttpCode)(import_common8.HttpStatus.NO_CONTENT),
|
|
1539
|
+
_ts_param4(0, (0, import_common8.Param)("id")),
|
|
1540
|
+
_ts_metadata5("design:type", Function),
|
|
1541
|
+
_ts_metadata5("design:paramtypes", [
|
|
1542
|
+
String
|
|
1543
|
+
]),
|
|
1544
|
+
_ts_metadata5("design:returntype", void 0)
|
|
1545
|
+
], AlertController.prototype, "deleteRule", null);
|
|
1546
|
+
_ts_decorate8([
|
|
1547
|
+
(0, import_common8.Put)(":id/acknowledge"),
|
|
1548
|
+
_ts_param4(0, (0, import_common8.Param)("id")),
|
|
1549
|
+
_ts_param4(1, (0, import_common8.Body)("userId")),
|
|
1550
|
+
_ts_metadata5("design:type", Function),
|
|
1551
|
+
_ts_metadata5("design:paramtypes", [
|
|
1552
|
+
String,
|
|
1553
|
+
String
|
|
1554
|
+
]),
|
|
1555
|
+
_ts_metadata5("design:returntype", void 0)
|
|
1556
|
+
], AlertController.prototype, "acknowledgeAlert", null);
|
|
1557
|
+
_ts_decorate8([
|
|
1558
|
+
(0, import_common8.Put)(":id/resolve"),
|
|
1559
|
+
_ts_param4(0, (0, import_common8.Param)("id")),
|
|
1560
|
+
_ts_param4(1, (0, import_common8.Body)("userId")),
|
|
1561
|
+
_ts_metadata5("design:type", Function),
|
|
1562
|
+
_ts_metadata5("design:paramtypes", [
|
|
1563
|
+
String,
|
|
1564
|
+
String
|
|
1565
|
+
]),
|
|
1566
|
+
_ts_metadata5("design:returntype", void 0)
|
|
1567
|
+
], AlertController.prototype, "resolveAlert", null);
|
|
1568
|
+
AlertController = _ts_decorate8([
|
|
1569
|
+
(0, import_common8.Controller)("monitoring/alerts"),
|
|
1570
|
+
Permissions(),
|
|
1571
|
+
_ts_metadata5("design:type", Function),
|
|
1572
|
+
_ts_metadata5("design:paramtypes", [
|
|
1573
|
+
typeof AlertManagerService === "undefined" ? Object : AlertManagerService
|
|
1574
|
+
])
|
|
1575
|
+
], AlertController);
|
|
1576
|
+
|
|
1577
|
+
// src/monitoring.module.ts
|
|
1578
|
+
function _ts_decorate9(decorators, target, key, desc) {
|
|
1579
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1580
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1581
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1582
|
+
} else {
|
|
1583
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
1584
|
+
if (d = decorators[i]) {
|
|
1585
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1590
|
+
}
|
|
1591
|
+
__name(_ts_decorate9, "_ts_decorate");
|
|
1592
|
+
var METRICS_COLLECTOR = /* @__PURE__ */ Symbol("METRICS_COLLECTOR");
|
|
1593
|
+
var ZuckerMonitoringModule = class {
|
|
1594
|
+
static {
|
|
1595
|
+
__name(this, "ZuckerMonitoringModule");
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
ZuckerMonitoringModule = _ts_decorate9([
|
|
1599
|
+
(0, import_common9.Global)(),
|
|
1600
|
+
(0, import_common9.Module)({
|
|
1601
|
+
controllers: [
|
|
1602
|
+
HealthController,
|
|
1603
|
+
PrometheusExporter,
|
|
1604
|
+
AlertController
|
|
1605
|
+
],
|
|
1606
|
+
providers: [
|
|
1607
|
+
ErrorTracker,
|
|
1608
|
+
HealthCheckService,
|
|
1609
|
+
MetricsRegistry,
|
|
1610
|
+
SystemMetricsCollector,
|
|
1611
|
+
AlertManagerService,
|
|
1612
|
+
{
|
|
1613
|
+
provide: METRICS_COLLECTOR,
|
|
1614
|
+
useClass: InMemoryMetricsCollector
|
|
1615
|
+
}
|
|
1616
|
+
],
|
|
1617
|
+
exports: [
|
|
1618
|
+
ErrorTracker,
|
|
1619
|
+
HealthCheckService,
|
|
1620
|
+
MetricsRegistry,
|
|
1621
|
+
SystemMetricsCollector,
|
|
1622
|
+
AlertManagerService,
|
|
1623
|
+
METRICS_COLLECTOR
|
|
1624
|
+
]
|
|
1625
|
+
})
|
|
1626
|
+
], ZuckerMonitoringModule);
|
|
1627
|
+
|
|
1628
|
+
// src/usage-tracker.ts
|
|
1629
|
+
var import_common10 = require("@nestjs/common");
|
|
1630
|
+
var import_node_async_hooks = require("async_hooks");
|
|
1631
|
+
function _ts_decorate10(decorators, target, key, desc) {
|
|
1632
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1633
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1634
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1635
|
+
} else {
|
|
1636
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
1637
|
+
if (d = decorators[i]) {
|
|
1638
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1643
|
+
}
|
|
1644
|
+
__name(_ts_decorate10, "_ts_decorate");
|
|
1645
|
+
var UsageContext = class UsageContext2 {
|
|
1646
|
+
static {
|
|
1647
|
+
__name(this, "UsageContext");
|
|
1648
|
+
}
|
|
1649
|
+
startTime = Date.now();
|
|
1650
|
+
counters = /* @__PURE__ */ new Map();
|
|
1651
|
+
increment(type, amount = 1) {
|
|
1652
|
+
const current = this.counters.get(type) ?? 0;
|
|
1653
|
+
this.counters.set(type, current + amount);
|
|
1654
|
+
}
|
|
1655
|
+
get(type) {
|
|
1656
|
+
return this.counters.get(type) ?? 0;
|
|
1657
|
+
}
|
|
1658
|
+
toSummary() {
|
|
1659
|
+
const metrics = {};
|
|
1660
|
+
for (const [key, value] of this.counters) {
|
|
1661
|
+
metrics[key] = value;
|
|
1662
|
+
}
|
|
1663
|
+
return {
|
|
1664
|
+
metrics,
|
|
1665
|
+
startTime: this.startTime,
|
|
1666
|
+
elapsed: Date.now() - this.startTime
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
};
|
|
1670
|
+
var storage = new import_node_async_hooks.AsyncLocalStorage();
|
|
1671
|
+
var UsageTracker = class _UsageTracker {
|
|
1672
|
+
static {
|
|
1673
|
+
__name(this, "UsageTracker");
|
|
1674
|
+
}
|
|
1675
|
+
static logger = new import_common10.Logger(_UsageTracker.name);
|
|
1676
|
+
/**
|
|
1677
|
+
* 在新的追踪上下文中执行函数
|
|
1678
|
+
*/
|
|
1679
|
+
static runWithContext(fn) {
|
|
1680
|
+
return storage.run(new UsageContext(), fn);
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* 记录一次资源使用
|
|
1684
|
+
* @param type 资源类型(如 'db_query', 'cache_hit', 'cache_miss', 'storage_read', 'api_call')
|
|
1685
|
+
* @param amount 使用量(默认 1)
|
|
1686
|
+
*/
|
|
1687
|
+
static track(type, amount = 1) {
|
|
1688
|
+
const ctx = storage.getStore();
|
|
1689
|
+
if (ctx) {
|
|
1690
|
+
ctx.increment(type, amount);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* 获取指定类型的当前计数
|
|
1695
|
+
*/
|
|
1696
|
+
static getCount(type) {
|
|
1697
|
+
return storage.getStore()?.get(type) ?? 0;
|
|
1698
|
+
}
|
|
1699
|
+
/**
|
|
1700
|
+
* 获取当前请求的使用汇总
|
|
1701
|
+
*/
|
|
1702
|
+
static getSummary() {
|
|
1703
|
+
return storage.getStore()?.toSummary();
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* 检查是否在追踪上下文中
|
|
1707
|
+
*/
|
|
1708
|
+
static isTracking() {
|
|
1709
|
+
return storage.getStore() !== void 0;
|
|
1710
|
+
}
|
|
1711
|
+
// ─── 实例方法(通过 NestJS DI 注入) ──────────────────────────────
|
|
1712
|
+
track(type, amount = 1) {
|
|
1713
|
+
_UsageTracker.track(type, amount);
|
|
1714
|
+
}
|
|
1715
|
+
getSummary() {
|
|
1716
|
+
return _UsageTracker.getSummary();
|
|
1717
|
+
}
|
|
1718
|
+
};
|
|
1719
|
+
UsageTracker = _ts_decorate10([
|
|
1720
|
+
(0, import_common10.Injectable)()
|
|
1721
|
+
], UsageTracker);
|
|
1722
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1723
|
+
0 && (module.exports = {
|
|
1724
|
+
AlertController,
|
|
1725
|
+
AlertManagerService,
|
|
1726
|
+
Counter,
|
|
1727
|
+
ERROR_REPORTER,
|
|
1728
|
+
ErrorTracker,
|
|
1729
|
+
Gauge,
|
|
1730
|
+
HEALTH_OPTIONS,
|
|
1731
|
+
HealthCheckService,
|
|
1732
|
+
HealthController,
|
|
1733
|
+
HealthStatus,
|
|
1734
|
+
Histogram,
|
|
1735
|
+
InMemoryMetricsCollector,
|
|
1736
|
+
METRICS_COLLECTOR,
|
|
1737
|
+
Metrics,
|
|
1738
|
+
MetricsRegistry,
|
|
1739
|
+
NoopErrorReporter,
|
|
1740
|
+
PrometheusExporter,
|
|
1741
|
+
Summary,
|
|
1742
|
+
SystemMetricsCollector,
|
|
1743
|
+
Timer,
|
|
1744
|
+
UsageTracker,
|
|
1745
|
+
ZuckerMonitoringModule,
|
|
1746
|
+
getProcessUptime,
|
|
1747
|
+
renderPrometheusMetrics
|
|
1748
|
+
});
|