adonisjs-server-stats 1.6.2 → 1.6.11
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/README.md +1 -0
- package/dist/core/api-client.d.ts.map +1 -1
- package/dist/core/dashboard-api.d.ts +2 -1
- package/dist/core/dashboard-api.d.ts.map +1 -1
- package/dist/core/dashboard-data-controller.d.ts +2 -0
- package/dist/core/dashboard-data-controller.d.ts.map +1 -1
- package/dist/core/debug-data-controller.d.ts +1 -0
- package/dist/core/debug-data-controller.d.ts.map +1 -1
- package/dist/core/history-buffer.d.ts.map +1 -1
- package/dist/core/index.js +404 -361
- package/dist/core/server-stats-controller.d.ts +1 -0
- package/dist/core/server-stats-controller.d.ts.map +1 -1
- package/dist/core/sparkline.d.ts.map +1 -1
- package/dist/react/core/api-client.d.ts.map +1 -1
- package/dist/react/core/dashboard-api.d.ts +2 -1
- package/dist/react/core/dashboard-api.d.ts.map +1 -1
- package/dist/react/core/dashboard-data-controller.d.ts +2 -0
- package/dist/react/core/dashboard-data-controller.d.ts.map +1 -1
- package/dist/react/core/debug-data-controller.d.ts +1 -0
- package/dist/react/core/debug-data-controller.d.ts.map +1 -1
- package/dist/react/core/history-buffer.d.ts.map +1 -1
- package/dist/react/core/server-stats-controller.d.ts +1 -0
- package/dist/react/core/server-stats-controller.d.ts.map +1 -1
- package/dist/react/core/sparkline.d.ts.map +1 -1
- package/dist/src/collectors/app_collector.d.ts.map +1 -1
- package/dist/src/collectors/db_pool_collector.d.ts.map +1 -1
- package/dist/src/collectors/redis_collector.d.ts.map +1 -1
- package/dist/src/controller/debug_controller.d.ts +3 -1
- package/dist/src/controller/debug_controller.d.ts.map +1 -1
- package/dist/src/controller/debug_controller.js +25 -20
- package/dist/src/dashboard/chart_aggregator.js +42 -41
- package/dist/src/dashboard/dashboard_controller.d.ts.map +1 -1
- package/dist/src/dashboard/dashboard_controller.js +7 -5
- package/dist/src/dashboard/dashboard_store.d.ts +61 -19
- package/dist/src/dashboard/dashboard_store.d.ts.map +1 -1
- package/dist/src/dashboard/dashboard_store.js +677 -474
- package/dist/src/dashboard/integrations/config_inspector.d.ts +4 -0
- package/dist/src/dashboard/integrations/config_inspector.d.ts.map +1 -1
- package/dist/src/dashboard/integrations/config_inspector.js +16 -2
- package/dist/src/dashboard/migrator.d.ts.map +1 -1
- package/dist/src/dashboard/migrator.js +30 -4
- package/dist/src/data/data_access.d.ts.map +1 -1
- package/dist/src/data/data_access.js +40 -7
- package/dist/src/debug/debug_store.d.ts.map +1 -1
- package/dist/src/debug/debug_store.js +17 -7
- package/dist/src/debug/email_collector.d.ts +2 -0
- package/dist/src/debug/email_collector.d.ts.map +1 -1
- package/dist/src/debug/email_collector.js +17 -13
- package/dist/src/debug/event_collector.d.ts +7 -1
- package/dist/src/debug/event_collector.d.ts.map +1 -1
- package/dist/src/debug/event_collector.js +46 -17
- package/dist/src/debug/query_collector.d.ts +12 -0
- package/dist/src/debug/query_collector.d.ts.map +1 -1
- package/dist/src/debug/query_collector.js +35 -5
- package/dist/src/debug/ring_buffer.d.ts +14 -0
- package/dist/src/debug/ring_buffer.d.ts.map +1 -1
- package/dist/src/debug/ring_buffer.js +48 -2
- package/dist/src/debug/trace_collector.d.ts +1 -0
- package/dist/src/debug/trace_collector.d.ts.map +1 -1
- package/dist/src/debug/trace_collector.js +4 -1
- package/dist/src/define_config.d.ts.map +1 -1
- package/dist/src/define_config.js +5 -1
- package/dist/src/edge/client/dashboard.js +2 -2
- package/dist/src/edge/client/debug-panel-deferred.js +1 -1
- package/dist/src/edge/client/debug-panel.js +1 -1
- package/dist/src/edge/client/stats-bar.js +1 -1
- package/dist/src/edge/client-vue/dashboard.js +5 -5
- package/dist/src/edge/client-vue/debug-panel-deferred.js +2 -2
- package/dist/src/edge/client-vue/debug-panel.js +2 -2
- package/dist/src/edge/client-vue/stats-bar.js +3 -3
- package/dist/src/engine/request_metrics.d.ts.map +1 -1
- package/dist/src/engine/request_metrics.js +33 -3
- package/dist/src/log_stream/log_stream_provider.js +1 -1
- package/dist/src/log_stream/log_stream_service.d.ts +1 -0
- package/dist/src/log_stream/log_stream_service.d.ts.map +1 -1
- package/dist/src/log_stream/log_stream_service.js +13 -3
- package/dist/src/prometheus/prometheus_collector.d.ts +14 -3
- package/dist/src/prometheus/prometheus_collector.d.ts.map +1 -1
- package/dist/src/prometheus/prometheus_collector.js +209 -198
- package/dist/src/provider/server_stats_provider.d.ts.map +1 -1
- package/dist/src/provider/server_stats_provider.js +17 -31
- package/dist/src/stubs/config.stub +3 -0
- package/dist/src/types.d.ts +12 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/logger.d.ts +7 -5
- package/dist/src/utils/logger.d.ts.map +1 -1
- package/dist/src/utils/logger.js +27 -5
- package/package.json +6 -2
|
@@ -37,9 +37,39 @@ export class RequestMetrics {
|
|
|
37
37
|
let totalDuration = 0;
|
|
38
38
|
let errorCount = 0;
|
|
39
39
|
let validCount = 0;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// When the buffer is full (ring buffer mode), scan from the oldest
|
|
41
|
+
// entry (writeIndex) forward. Records are in chronological order
|
|
42
|
+
// within each wrap, so once we find one >= cutoff, all subsequent
|
|
43
|
+
// records in that direction are also valid — but since they wrap,
|
|
44
|
+
// we still need to check all slots. The key optimization is that
|
|
45
|
+
// we can skip already-overwritten (stale) slots efficiently.
|
|
46
|
+
if (this.count === this.maxRecords) {
|
|
47
|
+
// Full ring buffer — scan from writeIndex (oldest) to writeIndex-1 (newest)
|
|
48
|
+
for (let j = 0; j < this.maxRecords; j++) {
|
|
49
|
+
const idx = (this.writeIndex + j) % this.maxRecords;
|
|
50
|
+
const r = this.records[idx];
|
|
51
|
+
if (r.timestamp >= cutoff) {
|
|
52
|
+
validCount++;
|
|
53
|
+
totalDuration += r.durationMs;
|
|
54
|
+
if (r.statusCode >= 500) {
|
|
55
|
+
errorCount++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Buffer not yet full — records are in order 0..count-1
|
|
62
|
+
// Scan backwards from newest to find the cutoff point, then
|
|
63
|
+
// aggregate only the valid tail.
|
|
64
|
+
let startIdx = 0;
|
|
65
|
+
for (let i = this.count - 1; i >= 0; i--) {
|
|
66
|
+
if (this.records[i].timestamp < cutoff) {
|
|
67
|
+
startIdx = i + 1;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (let i = startIdx; i < this.count; i++) {
|
|
72
|
+
const r = this.records[i];
|
|
43
73
|
validCount++;
|
|
44
74
|
totalDuration += r.durationMs;
|
|
45
75
|
if (r.statusCode >= 500) {
|
|
@@ -21,7 +21,7 @@ export default class LogStreamProvider {
|
|
|
21
21
|
const channelName = this.app.config.get('server_stats.logChannelName', 'admin/logs');
|
|
22
22
|
const broadcast = (entry) => {
|
|
23
23
|
try {
|
|
24
|
-
transmit.broadcast(channelName,
|
|
24
|
+
transmit.broadcast(channelName, entry);
|
|
25
25
|
}
|
|
26
26
|
catch {
|
|
27
27
|
// Silently ignore broadcast errors
|
|
@@ -2,6 +2,7 @@ import type { LogStats } from '../types.js';
|
|
|
2
2
|
export declare function parseAndEnrich(line: string): Record<string, unknown> | null;
|
|
3
3
|
export declare class LogStreamService {
|
|
4
4
|
private recentEntries;
|
|
5
|
+
private static readonly MAX_RECENT_ENTRIES;
|
|
5
6
|
private lastSize;
|
|
6
7
|
private intervalId;
|
|
7
8
|
private logPath;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log_stream_service.d.ts","sourceRoot":"","sources":["../../../src/log_stream/log_stream_service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAoB3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAY3E;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,OAAO,CAAC,CAA0C;gBAE9C,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;IAKhF;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"log_stream_service.d.ts","sourceRoot":"","sources":["../../../src/log_stream/log_stream_service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAoB3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAY3E;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IACnD,OAAO,CAAC,QAAQ,CAAI;IACpB,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,OAAO,CAAC,CAA0C;gBAE9C,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI;IAKhF;;;;;OAKG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAUrC,WAAW,IAAI,QAAQ;IAgCjB,KAAK;IAkBX,IAAI;YAOU,cAAc;CAiC7B"}
|
|
@@ -27,6 +27,7 @@ export function parseAndEnrich(line) {
|
|
|
27
27
|
}
|
|
28
28
|
export class LogStreamService {
|
|
29
29
|
recentEntries = [];
|
|
30
|
+
static MAX_RECENT_ENTRIES = 10_000;
|
|
30
31
|
lastSize = 0;
|
|
31
32
|
intervalId = null;
|
|
32
33
|
logPath;
|
|
@@ -43,15 +44,24 @@ export class LogStreamService {
|
|
|
43
44
|
*/
|
|
44
45
|
ingest(entry) {
|
|
45
46
|
const level = typeof entry.level === 'number' ? entry.level : 30;
|
|
47
|
+
// Cap the array to prevent unbounded growth under high log volume
|
|
48
|
+
if (this.recentEntries.length >= LogStreamService.MAX_RECENT_ENTRIES) {
|
|
49
|
+
this.recentEntries.splice(0, Math.floor(LogStreamService.MAX_RECENT_ENTRIES / 4));
|
|
50
|
+
}
|
|
46
51
|
this.recentEntries.push({ time: Date.now(), level });
|
|
47
52
|
this.onEntry?.(entry);
|
|
48
53
|
}
|
|
49
54
|
getLogStats() {
|
|
50
55
|
const now = Date.now();
|
|
51
56
|
const cutoff = now - ROLLING_WINDOW_MS;
|
|
52
|
-
// Prune old entries
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
// Prune old entries using splice (O(1) amortized) instead of
|
|
58
|
+
// repeated shift() which is O(N) per call
|
|
59
|
+
let pruneEnd = 0;
|
|
60
|
+
while (pruneEnd < this.recentEntries.length && this.recentEntries[pruneEnd].time < cutoff) {
|
|
61
|
+
pruneEnd++;
|
|
62
|
+
}
|
|
63
|
+
if (pruneEnd > 0) {
|
|
64
|
+
this.recentEntries.splice(0, pruneEnd);
|
|
55
65
|
}
|
|
56
66
|
let errors = 0;
|
|
57
67
|
let warnings = 0;
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import type { ServerStats } from '../types.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Returns a Prometheus collector config provider for server-stats metrics.
|
|
4
|
+
*
|
|
5
|
+
* The return type is a plain `{ resolver }` object instead of the concrete
|
|
6
|
+
* `ConfigProvider<Collector>` type. This avoids type incompatibilities when
|
|
7
|
+
* the package is symlinked via `file:` dependency — TypeScript would otherwise
|
|
8
|
+
* see two different copies of `@adonisjs/core` types and reject the assignment.
|
|
9
|
+
*
|
|
10
|
+
* At runtime the shape is identical to `configProvider.create(...)`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function serverStatsCollector(): {
|
|
13
|
+
type: 'provider';
|
|
14
|
+
resolver: (app: any) => Promise<any>;
|
|
15
|
+
};
|
|
5
16
|
export declare const ServerStatsCollector: {
|
|
6
17
|
instance: {
|
|
7
18
|
update(stats: Partial<ServerStats>): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prometheus_collector.d.ts","sourceRoot":"","sources":["../../../src/prometheus/prometheus_collector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prometheus_collector.d.ts","sourceRoot":"","sources":["../../../src/prometheus/prometheus_collector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;CAAE,CAkNjG;AAED,eAAO,MAAM,oBAAoB,EAAE;IACjC,QAAQ,EAAE;QAAE,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;CAG/D,CAAA"}
|
|
@@ -1,203 +1,214 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Returns a Prometheus collector config provider for server-stats metrics.
|
|
3
|
+
*
|
|
4
|
+
* The return type is a plain `{ resolver }` object instead of the concrete
|
|
5
|
+
* `ConfigProvider<Collector>` type. This avoids type incompatibilities when
|
|
6
|
+
* the package is symlinked via `file:` dependency — TypeScript would otherwise
|
|
7
|
+
* see two different copies of `@adonisjs/core` types and reject the assignment.
|
|
8
|
+
*
|
|
9
|
+
* At runtime the shape is identical to `configProvider.create(...)`.
|
|
10
|
+
*/
|
|
2
11
|
export function serverStatsCollector() {
|
|
3
|
-
return
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
12
|
+
return {
|
|
13
|
+
type: 'provider',
|
|
14
|
+
resolver: async (app) => {
|
|
15
|
+
const { Collector } = await import('@julr/adonisjs-prometheus/collectors/collector');
|
|
16
|
+
const config = app.config.get('prometheus', {});
|
|
17
|
+
class ServerStatsCollectorImpl extends Collector {
|
|
18
|
+
static instance = null;
|
|
19
|
+
// Process
|
|
20
|
+
cpuPercent;
|
|
21
|
+
eventLoopLag;
|
|
22
|
+
// DB Pool
|
|
23
|
+
dbPoolUsed;
|
|
24
|
+
dbPoolFree;
|
|
25
|
+
dbPoolPending;
|
|
26
|
+
dbPoolMax;
|
|
27
|
+
// Redis
|
|
28
|
+
redisUp;
|
|
29
|
+
redisMemoryUsedMb;
|
|
30
|
+
redisConnectedClients;
|
|
31
|
+
redisKeysCount;
|
|
32
|
+
redisHitRatePercent;
|
|
33
|
+
// Queue
|
|
34
|
+
queueActiveJobs;
|
|
35
|
+
queueWaitingJobs;
|
|
36
|
+
queueDelayedJobs;
|
|
37
|
+
queueFailedJobs;
|
|
38
|
+
queueWorkerCount;
|
|
39
|
+
// System
|
|
40
|
+
systemLoadAvg;
|
|
41
|
+
systemMemoryUsedMb;
|
|
42
|
+
systemMemoryTotalMb;
|
|
43
|
+
// App
|
|
44
|
+
appOnlineUsers;
|
|
45
|
+
appPendingWebhooks;
|
|
46
|
+
appPendingEmails;
|
|
47
|
+
register() {
|
|
48
|
+
ServerStatsCollectorImpl.instance = this;
|
|
49
|
+
ServerStatsCollector.instance = this;
|
|
50
|
+
this.#registerProcessGauges();
|
|
51
|
+
this.#registerDbPoolGauges();
|
|
52
|
+
this.#registerRedisGauges();
|
|
53
|
+
this.#registerQueueGauges();
|
|
54
|
+
this.#registerSystemGauges();
|
|
55
|
+
this.#registerAppGauges();
|
|
56
|
+
}
|
|
57
|
+
#registerProcessGauges() {
|
|
58
|
+
this.cpuPercent = this.createGauge({
|
|
59
|
+
name: this.buildMetricName('nodejs_cpu_usage_percent'),
|
|
60
|
+
help: 'Node.js CPU usage percentage',
|
|
61
|
+
});
|
|
62
|
+
this.eventLoopLag = this.createGauge({
|
|
63
|
+
name: this.buildMetricName('nodejs_event_loop_lag_ms'),
|
|
64
|
+
help: 'Node.js event loop lag in milliseconds',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
#registerDbPoolGauges() {
|
|
68
|
+
this.dbPoolUsed = this.createGauge({
|
|
69
|
+
name: this.buildMetricName('db_pool_used'),
|
|
70
|
+
help: 'Number of used database pool connections',
|
|
71
|
+
});
|
|
72
|
+
this.dbPoolFree = this.createGauge({
|
|
73
|
+
name: this.buildMetricName('db_pool_free'),
|
|
74
|
+
help: 'Number of free database pool connections',
|
|
75
|
+
});
|
|
76
|
+
this.dbPoolPending = this.createGauge({
|
|
77
|
+
name: this.buildMetricName('db_pool_pending'),
|
|
78
|
+
help: 'Number of pending database pool acquire requests',
|
|
79
|
+
});
|
|
80
|
+
this.dbPoolMax = this.createGauge({
|
|
81
|
+
name: this.buildMetricName('db_pool_max'),
|
|
82
|
+
help: 'Maximum database pool size',
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
#registerRedisGauges() {
|
|
86
|
+
this.redisUp = this.createGauge({
|
|
87
|
+
name: this.buildMetricName('redis_up'),
|
|
88
|
+
help: 'Whether Redis is reachable (0 or 1)',
|
|
89
|
+
});
|
|
90
|
+
this.redisMemoryUsedMb = this.createGauge({
|
|
91
|
+
name: this.buildMetricName('redis_memory_used_mb'),
|
|
92
|
+
help: 'Redis memory usage in megabytes',
|
|
93
|
+
});
|
|
94
|
+
this.redisConnectedClients = this.createGauge({
|
|
95
|
+
name: this.buildMetricName('redis_connected_clients'),
|
|
96
|
+
help: 'Number of connected Redis clients',
|
|
97
|
+
});
|
|
98
|
+
this.redisKeysCount = this.createGauge({
|
|
99
|
+
name: this.buildMetricName('redis_keys_count'),
|
|
100
|
+
help: 'Total number of Redis keys',
|
|
101
|
+
});
|
|
102
|
+
this.redisHitRatePercent = this.createGauge({
|
|
103
|
+
name: this.buildMetricName('redis_hit_rate_percent'),
|
|
104
|
+
help: 'Redis cache hit rate percentage',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
#registerQueueGauges() {
|
|
108
|
+
this.queueActiveJobs = this.createGauge({
|
|
109
|
+
name: this.buildMetricName('queue_active_jobs'),
|
|
110
|
+
help: 'Number of active queue jobs',
|
|
111
|
+
});
|
|
112
|
+
this.queueWaitingJobs = this.createGauge({
|
|
113
|
+
name: this.buildMetricName('queue_waiting_jobs'),
|
|
114
|
+
help: 'Number of waiting queue jobs',
|
|
115
|
+
});
|
|
116
|
+
this.queueDelayedJobs = this.createGauge({
|
|
117
|
+
name: this.buildMetricName('queue_delayed_jobs'),
|
|
118
|
+
help: 'Number of delayed queue jobs',
|
|
119
|
+
});
|
|
120
|
+
this.queueFailedJobs = this.createGauge({
|
|
121
|
+
name: this.buildMetricName('queue_failed_jobs'),
|
|
122
|
+
help: 'Number of failed queue jobs',
|
|
123
|
+
});
|
|
124
|
+
this.queueWorkerCount = this.createGauge({
|
|
125
|
+
name: this.buildMetricName('queue_worker_count'),
|
|
126
|
+
help: 'Number of active queue workers',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
#registerSystemGauges() {
|
|
130
|
+
this.systemLoadAvg = this.createGauge({
|
|
131
|
+
name: this.buildMetricName('system_load_avg'),
|
|
132
|
+
help: 'System load average',
|
|
133
|
+
labelNames: ['period'],
|
|
134
|
+
});
|
|
135
|
+
this.systemMemoryUsedMb = this.createGauge({
|
|
136
|
+
name: this.buildMetricName('system_memory_used_mb'),
|
|
137
|
+
help: 'System memory used in megabytes',
|
|
138
|
+
});
|
|
139
|
+
this.systemMemoryTotalMb = this.createGauge({
|
|
140
|
+
name: this.buildMetricName('system_memory_total_mb'),
|
|
141
|
+
help: 'System total memory in megabytes',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
#registerAppGauges() {
|
|
145
|
+
this.appOnlineUsers = this.createGauge({
|
|
146
|
+
name: this.buildMetricName('app_online_users'),
|
|
147
|
+
help: 'Number of online users (active sessions)',
|
|
148
|
+
});
|
|
149
|
+
this.appPendingWebhooks = this.createGauge({
|
|
150
|
+
name: this.buildMetricName('app_pending_webhooks'),
|
|
151
|
+
help: 'Number of pending webhook events',
|
|
152
|
+
});
|
|
153
|
+
this.appPendingEmails = this.createGauge({
|
|
154
|
+
name: this.buildMetricName('app_pending_emails'),
|
|
155
|
+
help: 'Number of pending scheduled emails',
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
update(stats) {
|
|
159
|
+
if (stats.cpuPercent !== undefined)
|
|
160
|
+
this.cpuPercent.set(stats.cpuPercent);
|
|
161
|
+
if (stats.eventLoopLag !== undefined)
|
|
162
|
+
this.eventLoopLag.set(stats.eventLoopLag);
|
|
163
|
+
if (stats.dbPoolUsed !== undefined)
|
|
164
|
+
this.dbPoolUsed.set(stats.dbPoolUsed);
|
|
165
|
+
if (stats.dbPoolFree !== undefined)
|
|
166
|
+
this.dbPoolFree.set(stats.dbPoolFree);
|
|
167
|
+
if (stats.dbPoolPending !== undefined)
|
|
168
|
+
this.dbPoolPending.set(stats.dbPoolPending);
|
|
169
|
+
if (stats.dbPoolMax !== undefined)
|
|
170
|
+
this.dbPoolMax.set(stats.dbPoolMax);
|
|
171
|
+
if (stats.redisOk !== undefined)
|
|
172
|
+
this.redisUp.set(stats.redisOk ? 1 : 0);
|
|
173
|
+
if (stats.redisMemoryUsedMb !== undefined)
|
|
174
|
+
this.redisMemoryUsedMb.set(stats.redisMemoryUsedMb);
|
|
175
|
+
if (stats.redisConnectedClients !== undefined)
|
|
176
|
+
this.redisConnectedClients.set(stats.redisConnectedClients);
|
|
177
|
+
if (stats.redisKeysCount !== undefined)
|
|
178
|
+
this.redisKeysCount.set(stats.redisKeysCount);
|
|
179
|
+
if (stats.redisHitRate !== undefined)
|
|
180
|
+
this.redisHitRatePercent.set(stats.redisHitRate);
|
|
181
|
+
if (stats.queueActive !== undefined)
|
|
182
|
+
this.queueActiveJobs.set(stats.queueActive);
|
|
183
|
+
if (stats.queueWaiting !== undefined)
|
|
184
|
+
this.queueWaitingJobs.set(stats.queueWaiting);
|
|
185
|
+
if (stats.queueDelayed !== undefined)
|
|
186
|
+
this.queueDelayedJobs.set(stats.queueDelayed);
|
|
187
|
+
if (stats.queueFailed !== undefined)
|
|
188
|
+
this.queueFailedJobs.set(stats.queueFailed);
|
|
189
|
+
if (stats.queueWorkerCount !== undefined)
|
|
190
|
+
this.queueWorkerCount.set(stats.queueWorkerCount);
|
|
191
|
+
if (stats.systemLoadAvg1m !== undefined)
|
|
192
|
+
this.systemLoadAvg.set({ period: '1m' }, stats.systemLoadAvg1m);
|
|
193
|
+
if (stats.systemLoadAvg5m !== undefined)
|
|
194
|
+
this.systemLoadAvg.set({ period: '5m' }, stats.systemLoadAvg5m);
|
|
195
|
+
if (stats.systemLoadAvg15m !== undefined)
|
|
196
|
+
this.systemLoadAvg.set({ period: '15m' }, stats.systemLoadAvg15m);
|
|
197
|
+
if (stats.systemMemoryTotalMb !== undefined && stats.systemMemoryFreeMb !== undefined)
|
|
198
|
+
this.systemMemoryUsedMb.set(stats.systemMemoryTotalMb - stats.systemMemoryFreeMb);
|
|
199
|
+
if (stats.systemMemoryTotalMb !== undefined)
|
|
200
|
+
this.systemMemoryTotalMb.set(stats.systemMemoryTotalMb);
|
|
201
|
+
if (stats.onlineUsers !== undefined)
|
|
202
|
+
this.appOnlineUsers.set(stats.onlineUsers);
|
|
203
|
+
if (stats.pendingWebhooks !== undefined)
|
|
204
|
+
this.appPendingWebhooks.set(stats.pendingWebhooks);
|
|
205
|
+
if (stats.pendingEmails !== undefined)
|
|
206
|
+
this.appPendingEmails.set(stats.pendingEmails);
|
|
207
|
+
}
|
|
46
208
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
help: 'Node.js CPU usage percentage',
|
|
51
|
-
});
|
|
52
|
-
this.eventLoopLag = this.createGauge({
|
|
53
|
-
name: this.buildMetricName('nodejs_event_loop_lag_ms'),
|
|
54
|
-
help: 'Node.js event loop lag in milliseconds',
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
#registerDbPoolGauges() {
|
|
58
|
-
this.dbPoolUsed = this.createGauge({
|
|
59
|
-
name: this.buildMetricName('db_pool_used'),
|
|
60
|
-
help: 'Number of used database pool connections',
|
|
61
|
-
});
|
|
62
|
-
this.dbPoolFree = this.createGauge({
|
|
63
|
-
name: this.buildMetricName('db_pool_free'),
|
|
64
|
-
help: 'Number of free database pool connections',
|
|
65
|
-
});
|
|
66
|
-
this.dbPoolPending = this.createGauge({
|
|
67
|
-
name: this.buildMetricName('db_pool_pending'),
|
|
68
|
-
help: 'Number of pending database pool acquire requests',
|
|
69
|
-
});
|
|
70
|
-
this.dbPoolMax = this.createGauge({
|
|
71
|
-
name: this.buildMetricName('db_pool_max'),
|
|
72
|
-
help: 'Maximum database pool size',
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
#registerRedisGauges() {
|
|
76
|
-
this.redisUp = this.createGauge({
|
|
77
|
-
name: this.buildMetricName('redis_up'),
|
|
78
|
-
help: 'Whether Redis is reachable (0 or 1)',
|
|
79
|
-
});
|
|
80
|
-
this.redisMemoryUsedMb = this.createGauge({
|
|
81
|
-
name: this.buildMetricName('redis_memory_used_mb'),
|
|
82
|
-
help: 'Redis memory usage in megabytes',
|
|
83
|
-
});
|
|
84
|
-
this.redisConnectedClients = this.createGauge({
|
|
85
|
-
name: this.buildMetricName('redis_connected_clients'),
|
|
86
|
-
help: 'Number of connected Redis clients',
|
|
87
|
-
});
|
|
88
|
-
this.redisKeysCount = this.createGauge({
|
|
89
|
-
name: this.buildMetricName('redis_keys_count'),
|
|
90
|
-
help: 'Total number of Redis keys',
|
|
91
|
-
});
|
|
92
|
-
this.redisHitRatePercent = this.createGauge({
|
|
93
|
-
name: this.buildMetricName('redis_hit_rate_percent'),
|
|
94
|
-
help: 'Redis cache hit rate percentage',
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
#registerQueueGauges() {
|
|
98
|
-
this.queueActiveJobs = this.createGauge({
|
|
99
|
-
name: this.buildMetricName('queue_active_jobs'),
|
|
100
|
-
help: 'Number of active queue jobs',
|
|
101
|
-
});
|
|
102
|
-
this.queueWaitingJobs = this.createGauge({
|
|
103
|
-
name: this.buildMetricName('queue_waiting_jobs'),
|
|
104
|
-
help: 'Number of waiting queue jobs',
|
|
105
|
-
});
|
|
106
|
-
this.queueDelayedJobs = this.createGauge({
|
|
107
|
-
name: this.buildMetricName('queue_delayed_jobs'),
|
|
108
|
-
help: 'Number of delayed queue jobs',
|
|
109
|
-
});
|
|
110
|
-
this.queueFailedJobs = this.createGauge({
|
|
111
|
-
name: this.buildMetricName('queue_failed_jobs'),
|
|
112
|
-
help: 'Number of failed queue jobs',
|
|
113
|
-
});
|
|
114
|
-
this.queueWorkerCount = this.createGauge({
|
|
115
|
-
name: this.buildMetricName('queue_worker_count'),
|
|
116
|
-
help: 'Number of active queue workers',
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
#registerSystemGauges() {
|
|
120
|
-
this.systemLoadAvg = this.createGauge({
|
|
121
|
-
name: this.buildMetricName('system_load_avg'),
|
|
122
|
-
help: 'System load average',
|
|
123
|
-
labelNames: ['period'],
|
|
124
|
-
});
|
|
125
|
-
this.systemMemoryUsedMb = this.createGauge({
|
|
126
|
-
name: this.buildMetricName('system_memory_used_mb'),
|
|
127
|
-
help: 'System memory used in megabytes',
|
|
128
|
-
});
|
|
129
|
-
this.systemMemoryTotalMb = this.createGauge({
|
|
130
|
-
name: this.buildMetricName('system_memory_total_mb'),
|
|
131
|
-
help: 'System total memory in megabytes',
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
#registerAppGauges() {
|
|
135
|
-
this.appOnlineUsers = this.createGauge({
|
|
136
|
-
name: this.buildMetricName('app_online_users'),
|
|
137
|
-
help: 'Number of online users (active sessions)',
|
|
138
|
-
});
|
|
139
|
-
this.appPendingWebhooks = this.createGauge({
|
|
140
|
-
name: this.buildMetricName('app_pending_webhooks'),
|
|
141
|
-
help: 'Number of pending webhook events',
|
|
142
|
-
});
|
|
143
|
-
this.appPendingEmails = this.createGauge({
|
|
144
|
-
name: this.buildMetricName('app_pending_emails'),
|
|
145
|
-
help: 'Number of pending scheduled emails',
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
update(stats) {
|
|
149
|
-
if (stats.cpuPercent !== undefined)
|
|
150
|
-
this.cpuPercent.set(stats.cpuPercent);
|
|
151
|
-
if (stats.eventLoopLag !== undefined)
|
|
152
|
-
this.eventLoopLag.set(stats.eventLoopLag);
|
|
153
|
-
if (stats.dbPoolUsed !== undefined)
|
|
154
|
-
this.dbPoolUsed.set(stats.dbPoolUsed);
|
|
155
|
-
if (stats.dbPoolFree !== undefined)
|
|
156
|
-
this.dbPoolFree.set(stats.dbPoolFree);
|
|
157
|
-
if (stats.dbPoolPending !== undefined)
|
|
158
|
-
this.dbPoolPending.set(stats.dbPoolPending);
|
|
159
|
-
if (stats.dbPoolMax !== undefined)
|
|
160
|
-
this.dbPoolMax.set(stats.dbPoolMax);
|
|
161
|
-
if (stats.redisOk !== undefined)
|
|
162
|
-
this.redisUp.set(stats.redisOk ? 1 : 0);
|
|
163
|
-
if (stats.redisMemoryUsedMb !== undefined)
|
|
164
|
-
this.redisMemoryUsedMb.set(stats.redisMemoryUsedMb);
|
|
165
|
-
if (stats.redisConnectedClients !== undefined)
|
|
166
|
-
this.redisConnectedClients.set(stats.redisConnectedClients);
|
|
167
|
-
if (stats.redisKeysCount !== undefined)
|
|
168
|
-
this.redisKeysCount.set(stats.redisKeysCount);
|
|
169
|
-
if (stats.redisHitRate !== undefined)
|
|
170
|
-
this.redisHitRatePercent.set(stats.redisHitRate);
|
|
171
|
-
if (stats.queueActive !== undefined)
|
|
172
|
-
this.queueActiveJobs.set(stats.queueActive);
|
|
173
|
-
if (stats.queueWaiting !== undefined)
|
|
174
|
-
this.queueWaitingJobs.set(stats.queueWaiting);
|
|
175
|
-
if (stats.queueDelayed !== undefined)
|
|
176
|
-
this.queueDelayedJobs.set(stats.queueDelayed);
|
|
177
|
-
if (stats.queueFailed !== undefined)
|
|
178
|
-
this.queueFailedJobs.set(stats.queueFailed);
|
|
179
|
-
if (stats.queueWorkerCount !== undefined)
|
|
180
|
-
this.queueWorkerCount.set(stats.queueWorkerCount);
|
|
181
|
-
if (stats.systemLoadAvg1m !== undefined)
|
|
182
|
-
this.systemLoadAvg.set({ period: '1m' }, stats.systemLoadAvg1m);
|
|
183
|
-
if (stats.systemLoadAvg5m !== undefined)
|
|
184
|
-
this.systemLoadAvg.set({ period: '5m' }, stats.systemLoadAvg5m);
|
|
185
|
-
if (stats.systemLoadAvg15m !== undefined)
|
|
186
|
-
this.systemLoadAvg.set({ period: '15m' }, stats.systemLoadAvg15m);
|
|
187
|
-
if (stats.systemMemoryTotalMb !== undefined && stats.systemMemoryFreeMb !== undefined)
|
|
188
|
-
this.systemMemoryUsedMb.set(stats.systemMemoryTotalMb - stats.systemMemoryFreeMb);
|
|
189
|
-
if (stats.systemMemoryTotalMb !== undefined)
|
|
190
|
-
this.systemMemoryTotalMb.set(stats.systemMemoryTotalMb);
|
|
191
|
-
if (stats.onlineUsers !== undefined)
|
|
192
|
-
this.appOnlineUsers.set(stats.onlineUsers);
|
|
193
|
-
if (stats.pendingWebhooks !== undefined)
|
|
194
|
-
this.appPendingWebhooks.set(stats.pendingWebhooks);
|
|
195
|
-
if (stats.pendingEmails !== undefined)
|
|
196
|
-
this.appPendingEmails.set(stats.pendingEmails);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return new ServerStatsCollectorImpl(config);
|
|
200
|
-
});
|
|
209
|
+
return new ServerStatsCollectorImpl(config);
|
|
210
|
+
},
|
|
211
|
+
};
|
|
201
212
|
}
|
|
202
213
|
export const ServerStatsCollector = {
|
|
203
214
|
instance: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server_stats_provider.d.ts","sourceRoot":"","sources":["../../../src/provider/server_stats_provider.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAQ9D,MAAM,CAAC,OAAO,OAAO,mBAAmB;IA2B1B,SAAS,CAAC,GAAG,EAAE,kBAAkB;IA1B7C,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,OAAO,CAAC,kBAAkB,CAAgC;IAC1D,OAAO,CAAC,uBAAuB,CAA8C;IAC7E,OAAO,CAAC,mBAAmB,CAA6C;IACxE,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,aAAa,CAA6B;IAGlD,OAAO,CAAC,sBAAsB,CAAgB;IAG9C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,gBAAgB,CAAiB;IACzC,OAAO,CAAC,gBAAgB,CAAiB;IACzC,OAAO,CAAC,iBAAiB,CAAiB;IAC1C,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,kBAAkB,CAAwB;gBAE5B,GAAG,EAAE,kBAAkB;IAEvC,IAAI;YAcI,cAAc;
|
|
1
|
+
{"version":3,"file":"server_stats_provider.d.ts","sourceRoot":"","sources":["../../../src/provider/server_stats_provider.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAQ9D,MAAM,CAAC,OAAO,OAAO,mBAAmB;IA2B1B,SAAS,CAAC,GAAG,EAAE,kBAAkB;IA1B7C,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,OAAO,CAAC,kBAAkB,CAAgC;IAC1D,OAAO,CAAC,uBAAuB,CAA8C;IAC7E,OAAO,CAAC,mBAAmB,CAA6C;IACxE,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,aAAa,CAA6B;IAGlD,OAAO,CAAC,sBAAsB,CAAgB;IAG9C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,gBAAgB,CAAiB;IACzC,OAAO,CAAC,gBAAgB,CAAiB;IACzC,OAAO,CAAC,iBAAiB,CAAiB;IAC1C,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,kBAAkB,CAAwB;gBAE5B,GAAG,EAAE,kBAAkB;IAEvC,IAAI;YAcI,cAAc;IAkJ5B;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;IAmDlC;;;;;;;OAOG;YACW,cAAc;IAqCtB,KAAK;YAuBG,qBAAqB;IAyFnC;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;YAwDZ,eAAe;IA8G7B;;;;;;OAMG;YACW,cAAc;IA2K5B,2DAA2D;IAC3D,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2ER,QAAQ;CAwCf"}
|