hono-status-monitor 1.0.0 → 1.0.2
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 +123 -4
- package/dist/cluster.d.ts +29 -0
- package/dist/cluster.d.ts.map +1 -0
- package/dist/cluster.js +256 -0
- package/dist/cluster.js.map +1 -0
- package/dist/dashboard.d.ts +13 -0
- package/dist/dashboard.d.ts.map +1 -1
- package/dist/dashboard.js +391 -0
- package/dist/dashboard.js.map +1 -1
- package/dist/index.d.ts +52 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -13
- package/dist/index.js.map +1 -1
- package/dist/monitor-edge.d.ts +21 -0
- package/dist/monitor-edge.d.ts.map +1 -0
- package/dist/monitor-edge.js +376 -0
- package/dist/monitor-edge.js.map +1 -0
- package/dist/monitor.d.ts.map +1 -1
- package/dist/monitor.js +41 -8
- package/dist/monitor.js.map +1 -1
- package/dist/platform.d.ts +33 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +80 -0
- package/dist/platform.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -9
package/README.md
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
Real-time server monitoring dashboard for **Hono.js** applications with WebSocket updates. Express-status-monitor style metrics powered by Socket.io.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
<img width="403" height="736" alt="Screenshot 2026-01-01 at 11 58 25 AM" src="https://github.com/user-attachments/assets/f793b5f0-a10e-4699-98ab-b4708703d024" />
|
|
9
|
+
|
|
9
10
|
|
|
10
11
|
## ✨ Features
|
|
11
12
|
|
|
@@ -111,7 +112,10 @@ const monitor = statusMonitor({
|
|
|
111
112
|
return path
|
|
112
113
|
.replace(/\/users\/\d+/g, '/users/:id')
|
|
113
114
|
.replace(/\/posts\/[a-f0-9]{24}/g, '/posts/:id');
|
|
114
|
-
}
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// Enable cluster mode for PM2 (auto-detected by default)
|
|
118
|
+
clusterMode: true
|
|
115
119
|
});
|
|
116
120
|
```
|
|
117
121
|
|
|
@@ -281,6 +285,67 @@ const monitor = statusMonitor({
|
|
|
281
285
|
});
|
|
282
286
|
```
|
|
283
287
|
|
|
288
|
+
### PM2 / Cluster Mode Support
|
|
289
|
+
|
|
290
|
+
To enable metrics aggregation across multiple processes (Cluster Mode), you need a specific entry point script that handles message relaying between workers.
|
|
291
|
+
|
|
292
|
+
1. **Create a `cluster.ts` (or `.js`) entry file:**
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import cluster from 'node:cluster';
|
|
296
|
+
import * as os from 'node:os';
|
|
297
|
+
import { dirname } from 'node:path';
|
|
298
|
+
import { fileURLToPath } from 'node:url';
|
|
299
|
+
|
|
300
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
301
|
+
const numCPUs = os.cpus().length;
|
|
302
|
+
|
|
303
|
+
if (cluster.isPrimary) {
|
|
304
|
+
console.log(`Primary ${process.pid} is running`);
|
|
305
|
+
|
|
306
|
+
// Fork workers
|
|
307
|
+
for (let i = 0; i < numCPUs; i++) {
|
|
308
|
+
const worker = cluster.fork();
|
|
309
|
+
|
|
310
|
+
// Relay messages between workers
|
|
311
|
+
worker.on('message', (message) => {
|
|
312
|
+
if (message?.type === 'worker-metrics') {
|
|
313
|
+
// Broadcast to all workers (including sender)
|
|
314
|
+
for (const id in cluster.workers) {
|
|
315
|
+
cluster.workers[id]?.send(message);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
cluster.on('exit', (worker) => {
|
|
322
|
+
console.log(`worker ${worker.process.pid} died`);
|
|
323
|
+
// Replace dead worker
|
|
324
|
+
const newWorker = cluster.fork();
|
|
325
|
+
newWorker.on('message', (message) => {
|
|
326
|
+
if (message?.type === 'worker-metrics') {
|
|
327
|
+
for (const id in cluster.workers) {
|
|
328
|
+
cluster.workers[id]?.send(message);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
} else {
|
|
334
|
+
// Workers share the TCP connection in this file
|
|
335
|
+
await import('./index'); // Path to your main app file
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
2. **Run this cluster script with PM2:**
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
# Start the cluster script as a SINGLE PM2 instance
|
|
343
|
+
# (The script itself manages the worker processes)
|
|
344
|
+
pm2 start cluster.ts --name my-app
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**Note:** Do NOT use `pm2 start app.ts -i max` directly, as PM2's default isolation prevents workers from sharing metrics without an external adapter (like Redis). Using the script above provides a zero-dependency aggregation solution.
|
|
348
|
+
|
|
284
349
|
## 🛡️ Security Considerations
|
|
285
350
|
|
|
286
351
|
The status dashboard exposes server metrics. Consider:
|
|
@@ -301,11 +366,64 @@ app.use('/status/*', basicAuth({
|
|
|
301
366
|
app.route('/status', monitor.routes);
|
|
302
367
|
```
|
|
303
368
|
|
|
369
|
+
## ☁️ Cloudflare Workers / Edge Support
|
|
370
|
+
|
|
371
|
+
This package automatically detects Cloudflare Workers and edge runtimes, providing a lightweight monitor with available metrics.
|
|
372
|
+
|
|
373
|
+
### Available Metrics in Edge Environments
|
|
374
|
+
|
|
375
|
+
| Metric | Available | Notes |
|
|
376
|
+
|--------|-----------|-------|
|
|
377
|
+
| Request count & RPS | ✅ | Fully supported |
|
|
378
|
+
| Response time percentiles | ✅ | P50, P95, P99, Avg |
|
|
379
|
+
| Status code breakdown | ✅ | 2xx, 3xx, 4xx, 5xx |
|
|
380
|
+
| Route analytics | ✅ | Top routes, slowest routes |
|
|
381
|
+
| Error tracking | ✅ | Recent errors with timestamps |
|
|
382
|
+
| CPU / Memory / Heap | ❌ | Not available in Workers |
|
|
383
|
+
| Event loop lag | ❌ | Not available in Workers |
|
|
384
|
+
| Load average | ❌ | Not available in Workers |
|
|
385
|
+
| WebSocket real-time | ❌ | Uses polling (5s interval) |
|
|
386
|
+
|
|
387
|
+
### Usage in Cloudflare Workers
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
import { Hono } from 'hono';
|
|
391
|
+
import { statusMonitor } from 'hono-status-monitor';
|
|
392
|
+
|
|
393
|
+
const app = new Hono();
|
|
394
|
+
|
|
395
|
+
// Create status monitor - automatically detects edge environment
|
|
396
|
+
const monitor = statusMonitor();
|
|
397
|
+
|
|
398
|
+
// Add middleware to track requests
|
|
399
|
+
app.use('*', monitor.middleware);
|
|
400
|
+
|
|
401
|
+
// Mount status dashboard
|
|
402
|
+
app.route('/status', monitor.routes);
|
|
403
|
+
|
|
404
|
+
// Your routes
|
|
405
|
+
app.get('/', (c) => c.text('Hello from Cloudflare Workers!'));
|
|
406
|
+
|
|
407
|
+
export default app;
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
> **Note:** In Cloudflare Workers, the dashboard uses HTTP polling (every 5 seconds) instead of WebSocket for updates. The dashboard will display an "Edge Mode" indicator.
|
|
411
|
+
|
|
412
|
+
### Force Edge Mode
|
|
413
|
+
|
|
414
|
+
You can explicitly use the edge-compatible monitor:
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
import { statusMonitorEdge } from 'hono-status-monitor';
|
|
418
|
+
|
|
419
|
+
const monitor = statusMonitorEdge();
|
|
420
|
+
```
|
|
421
|
+
|
|
304
422
|
## 📋 Requirements
|
|
305
423
|
|
|
306
|
-
- Node.js >= 18.0.0
|
|
424
|
+
- Node.js >= 18.0.0 (for Node.js mode)
|
|
307
425
|
- Hono.js >= 4.0.0
|
|
308
|
-
- @hono/node-server >= 1.0.0
|
|
426
|
+
- @hono/node-server >= 1.0.0 (for Node.js mode only)
|
|
309
427
|
|
|
310
428
|
## 🤝 Contributing
|
|
311
429
|
|
|
@@ -318,3 +436,4 @@ MIT © [Vinit Kumar Goel](https://github.com/vinitkumargoel)
|
|
|
318
436
|
---
|
|
319
437
|
|
|
320
438
|
Made with ❤️ for the Hono.js community
|
|
439
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { MetricsSnapshot, ChartData, WorkerInfo, WorkerMetricsMessage } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Check if running in cluster mode (PM2 or native Node.js cluster)
|
|
4
|
+
*/
|
|
5
|
+
export declare function isClusterWorker(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Check if this is the primary/master process
|
|
8
|
+
*/
|
|
9
|
+
export declare function isClusterMaster(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Get worker ID
|
|
12
|
+
*/
|
|
13
|
+
export declare function getWorkerId(): number;
|
|
14
|
+
/**
|
|
15
|
+
* Send metrics from worker to parent process (for PM2 cluster mode)
|
|
16
|
+
*/
|
|
17
|
+
export declare function sendMetricsToMaster(metrics: Partial<MetricsSnapshot>, charts: ChartData): void;
|
|
18
|
+
/**
|
|
19
|
+
* Create a cluster aggregator for the master process
|
|
20
|
+
*/
|
|
21
|
+
export declare function createClusterAggregator(): {
|
|
22
|
+
updateWorkerMetrics: (message: WorkerMetricsMessage) => void;
|
|
23
|
+
getWorkerInfo: () => WorkerInfo[];
|
|
24
|
+
aggregateMetrics: (baseSnapshot: MetricsSnapshot) => MetricsSnapshot;
|
|
25
|
+
aggregateCharts: (baseCharts: ChartData) => ChartData;
|
|
26
|
+
readonly workerCount: number;
|
|
27
|
+
};
|
|
28
|
+
export type ClusterAggregator = ReturnType<typeof createClusterAggregator>;
|
|
29
|
+
//# sourceMappingURL=cluster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../src/cluster.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACR,eAAe,EACf,SAAS,EACT,UAAU,EACV,oBAAoB,EAIvB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAUpC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,EACjC,MAAM,EAAE,SAAS,GAClB,IAAI,CAgBN;AAcD;;GAEG;AACH,wBAAgB,uBAAuB;mCAOG,oBAAoB,KAAG,IAAI;yBAwBvC,UAAU,EAAE;qCAeE,eAAe,KAAG,eAAe;kCAsHpC,SAAS,KAAG,SAAS;;EAsE7D;AAED,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
|
package/dist/cluster.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// HONO STATUS MONITOR - CLUSTER UTILITIES
|
|
3
|
+
// PM2 / Node.js Cluster mode support for metrics aggregation
|
|
4
|
+
// =============================================================================
|
|
5
|
+
import cluster from 'cluster';
|
|
6
|
+
/**
|
|
7
|
+
* Check if running in cluster mode (PM2 or native Node.js cluster)
|
|
8
|
+
*/
|
|
9
|
+
export function isClusterWorker() {
|
|
10
|
+
return cluster.isWorker || !!process.env.PM2_HOME || !!process.env.NODE_APP_INSTANCE;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Check if this is the primary/master process
|
|
14
|
+
*/
|
|
15
|
+
export function isClusterMaster() {
|
|
16
|
+
return cluster.isPrimary || cluster.isMaster;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get worker ID
|
|
20
|
+
*/
|
|
21
|
+
export function getWorkerId() {
|
|
22
|
+
if (cluster.worker) {
|
|
23
|
+
return cluster.worker.id;
|
|
24
|
+
}
|
|
25
|
+
// PM2 instance ID
|
|
26
|
+
const instanceId = process.env.NODE_APP_INSTANCE;
|
|
27
|
+
if (instanceId) {
|
|
28
|
+
return parseInt(instanceId, 10);
|
|
29
|
+
}
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Send metrics from worker to parent process (for PM2 cluster mode)
|
|
34
|
+
*/
|
|
35
|
+
export function sendMetricsToMaster(metrics, charts) {
|
|
36
|
+
if (!process.send)
|
|
37
|
+
return;
|
|
38
|
+
const message = {
|
|
39
|
+
type: 'worker-metrics',
|
|
40
|
+
workerId: getWorkerId(),
|
|
41
|
+
pid: process.pid,
|
|
42
|
+
metrics,
|
|
43
|
+
charts
|
|
44
|
+
};
|
|
45
|
+
try {
|
|
46
|
+
process.send(message);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
// Silently ignore send errors (master may have died)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create a cluster aggregator for the master process
|
|
54
|
+
*/
|
|
55
|
+
export function createClusterAggregator() {
|
|
56
|
+
const workerMetrics = {};
|
|
57
|
+
const WORKER_TIMEOUT_MS = 10000; // Consider worker dead after 10s no update
|
|
58
|
+
/**
|
|
59
|
+
* Update metrics from a worker
|
|
60
|
+
*/
|
|
61
|
+
function updateWorkerMetrics(message) {
|
|
62
|
+
workerMetrics[message.workerId] = {
|
|
63
|
+
pid: message.pid,
|
|
64
|
+
metrics: message.metrics,
|
|
65
|
+
charts: message.charts,
|
|
66
|
+
lastUpdate: Date.now()
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Clean up stale workers
|
|
71
|
+
*/
|
|
72
|
+
function cleanupStaleWorkers() {
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
for (const workerId of Object.keys(workerMetrics)) {
|
|
75
|
+
if (now - workerMetrics[parseInt(workerId)].lastUpdate > WORKER_TIMEOUT_MS) {
|
|
76
|
+
delete workerMetrics[parseInt(workerId)];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get all active worker info
|
|
82
|
+
*/
|
|
83
|
+
function getWorkerInfo() {
|
|
84
|
+
cleanupStaleWorkers();
|
|
85
|
+
return Object.values(workerMetrics).map(w => ({
|
|
86
|
+
pid: w.pid,
|
|
87
|
+
cpu: w.metrics.cpu || 0,
|
|
88
|
+
memoryMB: w.metrics.memoryMB || 0,
|
|
89
|
+
rps: w.metrics.rps || 0,
|
|
90
|
+
totalRequests: w.metrics.totalRequests || 0,
|
|
91
|
+
responseTime: w.metrics.responseTime || 0
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Aggregate metrics from all workers
|
|
96
|
+
*/
|
|
97
|
+
function aggregateMetrics(baseSnapshot) {
|
|
98
|
+
cleanupStaleWorkers();
|
|
99
|
+
const workers = Object.values(workerMetrics);
|
|
100
|
+
if (workers.length === 0) {
|
|
101
|
+
return baseSnapshot;
|
|
102
|
+
}
|
|
103
|
+
// Sum metrics that should be totaled across workers
|
|
104
|
+
let totalRps = 0;
|
|
105
|
+
let totalRequests = 0;
|
|
106
|
+
let totalActiveConnections = 0;
|
|
107
|
+
let totalErrorRate = 0;
|
|
108
|
+
// Average metrics that should be averaged
|
|
109
|
+
let totalCpu = 0;
|
|
110
|
+
let totalResponseTime = 0;
|
|
111
|
+
let workerCount = 0;
|
|
112
|
+
// Aggregate status codes
|
|
113
|
+
const aggregatedStatusCodes = {};
|
|
114
|
+
// Aggregate rate limit stats
|
|
115
|
+
let totalRateLimitBlocked = 0;
|
|
116
|
+
let totalRateLimitTotal = 0;
|
|
117
|
+
// Aggregate routes
|
|
118
|
+
const routeMap = new Map();
|
|
119
|
+
for (const worker of workers) {
|
|
120
|
+
const m = worker.metrics;
|
|
121
|
+
workerCount++;
|
|
122
|
+
// Sum
|
|
123
|
+
totalRps += m.rps || 0;
|
|
124
|
+
totalRequests += m.totalRequests || 0;
|
|
125
|
+
totalActiveConnections += m.activeConnections || 0;
|
|
126
|
+
// For averaging
|
|
127
|
+
totalCpu += m.cpu || 0;
|
|
128
|
+
totalResponseTime += m.responseTime || 0;
|
|
129
|
+
totalErrorRate += m.errorRate || 0;
|
|
130
|
+
// Aggregate status codes
|
|
131
|
+
if (m.statusCodes) {
|
|
132
|
+
for (const [code, count] of Object.entries(m.statusCodes)) {
|
|
133
|
+
aggregatedStatusCodes[code] = (aggregatedStatusCodes[code] || 0) + count;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Aggregate rate limit stats
|
|
137
|
+
if (m.rateLimitStats) {
|
|
138
|
+
totalRateLimitBlocked += m.rateLimitStats.blocked || 0;
|
|
139
|
+
totalRateLimitTotal += m.rateLimitStats.total || 0;
|
|
140
|
+
}
|
|
141
|
+
// Aggregate routes
|
|
142
|
+
const allRoutes = [
|
|
143
|
+
...(m.topRoutes || []),
|
|
144
|
+
...(m.slowestRoutes || []),
|
|
145
|
+
...(m.errorRoutes || [])
|
|
146
|
+
];
|
|
147
|
+
for (const route of allRoutes) {
|
|
148
|
+
const key = `${route.method}:${route.path}`;
|
|
149
|
+
const existing = routeMap.get(key);
|
|
150
|
+
if (existing) {
|
|
151
|
+
existing.count += route.count;
|
|
152
|
+
existing.totalTime += route.totalTime;
|
|
153
|
+
existing.avgTime = existing.totalTime / existing.count;
|
|
154
|
+
existing.minTime = Math.min(existing.minTime, route.minTime);
|
|
155
|
+
existing.maxTime = Math.max(existing.maxTime, route.maxTime);
|
|
156
|
+
existing.errors += route.errors;
|
|
157
|
+
existing.lastAccess = Math.max(existing.lastAccess, route.lastAccess);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
routeMap.set(key, { ...route });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Calculate averages
|
|
165
|
+
const avgCpu = workerCount > 0 ? totalCpu / workerCount : baseSnapshot.cpu;
|
|
166
|
+
const avgResponseTime = workerCount > 0 ? totalResponseTime / workerCount : baseSnapshot.responseTime;
|
|
167
|
+
const avgErrorRate = workerCount > 0 ? totalErrorRate / workerCount : baseSnapshot.errorRate;
|
|
168
|
+
// Get aggregated routes
|
|
169
|
+
const allRoutes = Array.from(routeMap.values());
|
|
170
|
+
const topRoutes = allRoutes.sort((a, b) => b.count - a.count).slice(0, 10);
|
|
171
|
+
const slowestRoutes = allRoutes.filter(r => r.count > 0).sort((a, b) => b.avgTime - a.avgTime).slice(0, 10);
|
|
172
|
+
const errorRoutes = allRoutes.filter(r => r.errors > 0).sort((a, b) => b.errors - a.errors).slice(0, 10);
|
|
173
|
+
return {
|
|
174
|
+
...baseSnapshot,
|
|
175
|
+
cpu: Math.round(avgCpu * 10) / 10,
|
|
176
|
+
responseTime: Math.round(avgResponseTime * 100) / 100,
|
|
177
|
+
rps: totalRps,
|
|
178
|
+
totalRequests,
|
|
179
|
+
activeConnections: totalActiveConnections,
|
|
180
|
+
errorRate: Math.round(avgErrorRate * 100) / 100,
|
|
181
|
+
statusCodes: Object.keys(aggregatedStatusCodes).length > 0
|
|
182
|
+
? aggregatedStatusCodes
|
|
183
|
+
: baseSnapshot.statusCodes,
|
|
184
|
+
rateLimitStats: {
|
|
185
|
+
blocked: totalRateLimitBlocked,
|
|
186
|
+
total: totalRateLimitTotal
|
|
187
|
+
},
|
|
188
|
+
topRoutes,
|
|
189
|
+
slowestRoutes,
|
|
190
|
+
errorRoutes,
|
|
191
|
+
workers: getWorkerInfo(),
|
|
192
|
+
workerCount
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Aggregate chart data from all workers
|
|
197
|
+
*/
|
|
198
|
+
function aggregateCharts(baseCharts) {
|
|
199
|
+
cleanupStaleWorkers();
|
|
200
|
+
const workers = Object.values(workerMetrics);
|
|
201
|
+
if (workers.length === 0) {
|
|
202
|
+
return baseCharts;
|
|
203
|
+
}
|
|
204
|
+
// For charts, we need to merge data points by timestamp
|
|
205
|
+
const mergeChartData = (base, workerCharts, key, aggregationType) => {
|
|
206
|
+
const timeMap = new Map();
|
|
207
|
+
// Add base data
|
|
208
|
+
for (const point of base) {
|
|
209
|
+
timeMap.set(point.timestamp, { sum: point.value, count: 1 });
|
|
210
|
+
}
|
|
211
|
+
// Add worker data
|
|
212
|
+
for (const wc of workerCharts) {
|
|
213
|
+
const data = wc[key];
|
|
214
|
+
for (const point of data) {
|
|
215
|
+
const existing = timeMap.get(point.timestamp);
|
|
216
|
+
if (existing) {
|
|
217
|
+
existing.sum += point.value;
|
|
218
|
+
existing.count++;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
timeMap.set(point.timestamp, { sum: point.value, count: 1 });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Convert back to array
|
|
226
|
+
const result = [];
|
|
227
|
+
for (const [timestamp, { sum, count }] of timeMap.entries()) {
|
|
228
|
+
const value = aggregationType === 'sum' ? sum : sum / count;
|
|
229
|
+
result.push({ timestamp, value: Math.round(value * 100) / 100 });
|
|
230
|
+
}
|
|
231
|
+
return result.sort((a, b) => a.timestamp - b.timestamp);
|
|
232
|
+
};
|
|
233
|
+
const workerCharts = workers.map(w => w.charts);
|
|
234
|
+
return {
|
|
235
|
+
cpu: mergeChartData(baseCharts.cpu, workerCharts, 'cpu', 'avg'),
|
|
236
|
+
memory: mergeChartData(baseCharts.memory, workerCharts, 'memory', 'avg'),
|
|
237
|
+
heap: mergeChartData(baseCharts.heap, workerCharts, 'heap', 'avg'),
|
|
238
|
+
loadAvg: mergeChartData(baseCharts.loadAvg, workerCharts, 'loadAvg', 'avg'),
|
|
239
|
+
responseTime: mergeChartData(baseCharts.responseTime, workerCharts, 'responseTime', 'avg'),
|
|
240
|
+
rps: mergeChartData(baseCharts.rps, workerCharts, 'rps', 'sum'),
|
|
241
|
+
eventLoopLag: mergeChartData(baseCharts.eventLoopLag, workerCharts, 'eventLoopLag', 'avg'),
|
|
242
|
+
errorRate: mergeChartData(baseCharts.errorRate, workerCharts, 'errorRate', 'avg')
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
updateWorkerMetrics,
|
|
247
|
+
getWorkerInfo,
|
|
248
|
+
aggregateMetrics,
|
|
249
|
+
aggregateCharts,
|
|
250
|
+
get workerCount() {
|
|
251
|
+
cleanupStaleWorkers();
|
|
252
|
+
return Object.keys(workerMetrics).length;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=cluster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster.js","sourceRoot":"","sources":["../src/cluster.ts"],"names":[],"mappings":"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"}
|
package/dist/dashboard.d.ts
CHANGED
|
@@ -3,4 +3,17 @@ import type { DashboardProps } from './types.js';
|
|
|
3
3
|
* Generate the status dashboard HTML
|
|
4
4
|
*/
|
|
5
5
|
export declare function generateDashboard({ hostname, uptime, socketPath, title }: DashboardProps): string;
|
|
6
|
+
/**
|
|
7
|
+
* Edge Dashboard Props (no socketPath)
|
|
8
|
+
*/
|
|
9
|
+
export interface EdgeDashboardProps {
|
|
10
|
+
hostname: string;
|
|
11
|
+
uptime: string;
|
|
12
|
+
title: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Generate the edge-compatible status dashboard HTML
|
|
16
|
+
* Uses polling instead of WebSocket, only shows available metrics
|
|
17
|
+
*/
|
|
18
|
+
export declare function generateEdgeDashboard({ hostname, uptime, title }: EdgeDashboardProps): string;
|
|
6
19
|
//# sourceMappingURL=dashboard.d.ts.map
|
package/dist/dashboard.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,cAAc,GAAG,MAAM,CA6bjG"}
|
|
1
|
+
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,cAAc,GAAG,MAAM,CA6bjG;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,kBAAkB,GAAG,MAAM,CAkY7F"}
|