@composed-di/observability 0.5.0-alpha
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/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +50 -0
- package/dist/cli.js.map +1 -0
- package/dist/dashboardClient.d.ts +67 -0
- package/dist/dashboardClient.d.ts.map +1 -0
- package/dist/dashboardClient.js +168 -0
- package/dist/dashboardClient.js.map +1 -0
- package/dist/dashboardEventListener.d.ts +32 -0
- package/dist/dashboardEventListener.d.ts.map +1 -0
- package/dist/dashboardEventListener.js +88 -0
- package/dist/dashboardEventListener.js.map +1 -0
- package/dist/dashboardHtml.d.ts +11 -0
- package/dist/dashboardHtml.d.ts.map +1 -0
- package/dist/dashboardHtml.js +662 -0
- package/dist/dashboardHtml.js.map +1 -0
- package/dist/dashboardServer.d.ts +99 -0
- package/dist/dashboardServer.d.ts.map +1 -0
- package/dist/dashboardServer.js +360 -0
- package/dist/dashboardServer.js.map +1 -0
- package/dist/events.d.ts +80 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +7 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/moduleGraph.d.ts +13 -0
- package/dist/moduleGraph.d.ts.map +1 -0
- package/dist/moduleGraph.js +25 -0
- package/dist/moduleGraph.js.map +1 -0
- package/package.json +47 -0
- package/src/cli.ts +42 -0
- package/src/dashboardClient.ts +189 -0
- package/src/dashboardEventListener.ts +104 -0
- package/src/dashboardHtml.ts +659 -0
- package/src/dashboardServer.ts +391 -0
- package/src/events.ts +94 -0
- package/src/index.ts +5 -0
- package/src/moduleGraph.ts +37 -0
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
/**
|
|
14
|
+
* Standalone dashboard server:
|
|
15
|
+
*
|
|
16
|
+
* composed-di-dashboard [--port 4321] [--host 127.0.0.1]
|
|
17
|
+
*
|
|
18
|
+
* Applications export their service events to it with DashboardClient.
|
|
19
|
+
*/
|
|
20
|
+
const dashboardServer_1 = require("./dashboardServer");
|
|
21
|
+
function argValue(flag) {
|
|
22
|
+
const index = process.argv.indexOf(flag);
|
|
23
|
+
return index >= 0 ? process.argv[index + 1] : undefined;
|
|
24
|
+
}
|
|
25
|
+
function main() {
|
|
26
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
var _a, _b, _c, _d;
|
|
28
|
+
const port = Number((_b = (_a = argValue('--port')) !== null && _a !== void 0 ? _a : process.env.PORT) !== null && _b !== void 0 ? _b : 4321);
|
|
29
|
+
const host = (_c = argValue('--host')) !== null && _c !== void 0 ? _c : '127.0.0.1';
|
|
30
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
31
|
+
console.error(`Invalid port: ${(_d = argValue('--port')) !== null && _d !== void 0 ? _d : process.env.PORT}`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const dashboard = new dashboardServer_1.ServiceDashboard();
|
|
35
|
+
const url = yield dashboard.listen(port, host);
|
|
36
|
+
console.log(`composed-di dashboard listening at ${url}`);
|
|
37
|
+
console.log('Waiting for an application to connect (see DashboardClient in @composed-di/observability).');
|
|
38
|
+
const shutdown = () => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
yield dashboard.close();
|
|
40
|
+
process.exit(0);
|
|
41
|
+
});
|
|
42
|
+
process.on('SIGINT', shutdown);
|
|
43
|
+
process.on('SIGTERM', shutdown);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
main().catch((error) => {
|
|
47
|
+
console.error(error);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA;;;;;;GAMG;AACH,uDAAqD;AAErD,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,CAAC;AAED,SAAe,IAAI;;;QACjB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAA,MAAA,QAAQ,CAAC,QAAQ,CAAC,mCAAI,OAAO,CAAC,GAAG,CAAC,IAAI,mCAAI,IAAI,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,MAAA,QAAQ,CAAC,QAAQ,CAAC,mCAAI,WAAW,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;YACxD,OAAO,CAAC,KAAK,CAAC,iBAAiB,MAAA,QAAQ,CAAC,QAAQ,CAAC,mCAAI,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,kCAAgB,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,sCAAsC,GAAG,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CACT,4FAA4F,CAC7F,CAAC;QAEF,MAAM,QAAQ,GAAG,GAAS,EAAE;YAC1B,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAA,CAAC;QACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;CAAA;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ServiceModule } from '@composed-di/core';
|
|
2
|
+
import { DashboardEventListener } from './dashboardEventListener';
|
|
3
|
+
export interface DashboardClientOptions {
|
|
4
|
+
/** Base URL of the standalone dashboard server, e.g. "http://localhost:4321". */
|
|
5
|
+
url: string;
|
|
6
|
+
/** How long to buffer events before exporting a batch. Default 250ms. */
|
|
7
|
+
flushIntervalMs?: number;
|
|
8
|
+
/** Export immediately once this many events are buffered. Default 64. */
|
|
9
|
+
maxBatchSize?: number;
|
|
10
|
+
/** Events kept while the server is unreachable; oldest are dropped. Default 5000. */
|
|
11
|
+
maxQueueSize?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Called when an export fails. Defaults to a single console.warn per
|
|
14
|
+
* failure streak; exports never throw into application code.
|
|
15
|
+
*/
|
|
16
|
+
onError?: (error: Error) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Exports service observability to a standalone dashboard server, the way
|
|
20
|
+
* an OpenTelemetry SDK exports spans to a collector.
|
|
21
|
+
*
|
|
22
|
+
* The application owns only this client: pass `client.listener` to
|
|
23
|
+
* `ServiceModule.from`, then `attach` the module to register its dependency
|
|
24
|
+
* graph with the server. Span events are buffered and shipped in batches;
|
|
25
|
+
* export failures are retried on the next flush and never affect the
|
|
26
|
+
* application.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* const client = new DashboardClient({ url: 'http://localhost:4321' });
|
|
31
|
+
* const module = ServiceModule.from(factories, client.listener);
|
|
32
|
+
* client.attach(module);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare class DashboardClient {
|
|
36
|
+
/** Pass this as the second argument to ServiceModule.from. */
|
|
37
|
+
readonly listener: DashboardEventListener;
|
|
38
|
+
private readonly url;
|
|
39
|
+
private readonly flushIntervalMs;
|
|
40
|
+
private readonly maxBatchSize;
|
|
41
|
+
private readonly maxQueueSize;
|
|
42
|
+
private readonly onError;
|
|
43
|
+
private queue;
|
|
44
|
+
private graph;
|
|
45
|
+
private graphSent;
|
|
46
|
+
private timer;
|
|
47
|
+
/** Serializes exports so events reach the server in order. */
|
|
48
|
+
private exporting;
|
|
49
|
+
private warned;
|
|
50
|
+
private closed;
|
|
51
|
+
constructor({ url, flushIntervalMs, maxBatchSize, maxQueueSize, onError, }: DashboardClientOptions);
|
|
52
|
+
/**
|
|
53
|
+
* Registers the module's dependency graph with the dashboard server.
|
|
54
|
+
*/
|
|
55
|
+
attach(module: ServiceModule): this;
|
|
56
|
+
/** Exports everything buffered so far. Resolves once the attempt finishes. */
|
|
57
|
+
flush(): Promise<void>;
|
|
58
|
+
/** Flushes remaining events and stops the export timer. */
|
|
59
|
+
close(): Promise<void>;
|
|
60
|
+
private enqueue;
|
|
61
|
+
private scheduleFlush;
|
|
62
|
+
private export;
|
|
63
|
+
/** After a failed export, retry even if no new events arrive. */
|
|
64
|
+
private retryLater;
|
|
65
|
+
private post;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=dashboardClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboardClient.d.ts","sourceRoot":"","sources":["../src/dashboardClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAIlE,MAAM,WAAW,sBAAsB;IACrC,iFAAiF;IACjF,GAAG,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,eAAe;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,yBAAgC;IAEjD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IAEjD,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAA+B;IAC5C,8DAA8D;IAC9D,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,EACV,GAAG,EACH,eAAqB,EACrB,YAAiB,EACjB,YAAmB,EACnB,OAAO,GACR,EAAE,sBAAsB;IAiBzB;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAOnC,8EAA8E;IAC9E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,2DAA2D;IACrD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,OAAO;IAaf,OAAO,CAAC,aAAa;YASP,MAAM;IAgCpB,iEAAiE;IACjE,OAAO,CAAC,UAAU;YAMJ,IAAI;CAqBnB"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DashboardClient = void 0;
|
|
13
|
+
const dashboardEventListener_1 = require("./dashboardEventListener");
|
|
14
|
+
const moduleGraph_1 = require("./moduleGraph");
|
|
15
|
+
/**
|
|
16
|
+
* Exports service observability to a standalone dashboard server, the way
|
|
17
|
+
* an OpenTelemetry SDK exports spans to a collector.
|
|
18
|
+
*
|
|
19
|
+
* The application owns only this client: pass `client.listener` to
|
|
20
|
+
* `ServiceModule.from`, then `attach` the module to register its dependency
|
|
21
|
+
* graph with the server. Span events are buffered and shipped in batches;
|
|
22
|
+
* export failures are retried on the next flush and never affect the
|
|
23
|
+
* application.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const client = new DashboardClient({ url: 'http://localhost:4321' });
|
|
28
|
+
* const module = ServiceModule.from(factories, client.listener);
|
|
29
|
+
* client.attach(module);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
class DashboardClient {
|
|
33
|
+
constructor({ url, flushIntervalMs = 250, maxBatchSize = 64, maxQueueSize = 5000, onError, }) {
|
|
34
|
+
/** Pass this as the second argument to ServiceModule.from. */
|
|
35
|
+
this.listener = new dashboardEventListener_1.DashboardEventListener();
|
|
36
|
+
this.queue = [];
|
|
37
|
+
this.graph = null;
|
|
38
|
+
this.graphSent = false;
|
|
39
|
+
this.timer = null;
|
|
40
|
+
/** Serializes exports so events reach the server in order. */
|
|
41
|
+
this.exporting = Promise.resolve();
|
|
42
|
+
this.warned = false;
|
|
43
|
+
this.closed = false;
|
|
44
|
+
this.url = url.replace(/\/$/, '');
|
|
45
|
+
this.flushIntervalMs = flushIntervalMs;
|
|
46
|
+
this.maxBatchSize = maxBatchSize;
|
|
47
|
+
this.maxQueueSize = maxQueueSize;
|
|
48
|
+
this.onError =
|
|
49
|
+
onError !== null && onError !== void 0 ? onError : ((error) => {
|
|
50
|
+
if (this.warned)
|
|
51
|
+
return;
|
|
52
|
+
this.warned = true;
|
|
53
|
+
console.warn(`[composed-di] dashboard export to ${this.url} failed (will keep retrying): ${error.message}`);
|
|
54
|
+
});
|
|
55
|
+
this.listener.subscribe((event) => this.enqueue(event));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Registers the module's dependency graph with the dashboard server.
|
|
59
|
+
*/
|
|
60
|
+
attach(module) {
|
|
61
|
+
this.graph = (0, moduleGraph_1.moduleGraph)(module);
|
|
62
|
+
this.graphSent = false;
|
|
63
|
+
void this.flush();
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
/** Exports everything buffered so far. Resolves once the attempt finishes. */
|
|
67
|
+
flush() {
|
|
68
|
+
this.exporting = this.exporting.then(() => this.export());
|
|
69
|
+
return this.exporting;
|
|
70
|
+
}
|
|
71
|
+
/** Flushes remaining events and stops the export timer. */
|
|
72
|
+
close() {
|
|
73
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
this.closed = true;
|
|
75
|
+
if (this.timer) {
|
|
76
|
+
clearTimeout(this.timer);
|
|
77
|
+
this.timer = null;
|
|
78
|
+
}
|
|
79
|
+
yield this.flush();
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
enqueue(event) {
|
|
83
|
+
if (this.closed)
|
|
84
|
+
return;
|
|
85
|
+
this.queue.push(event);
|
|
86
|
+
if (this.queue.length > this.maxQueueSize) {
|
|
87
|
+
this.queue.splice(0, this.queue.length - this.maxQueueSize);
|
|
88
|
+
}
|
|
89
|
+
if (this.queue.length >= this.maxBatchSize) {
|
|
90
|
+
void this.flush();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.scheduleFlush(this.flushIntervalMs);
|
|
94
|
+
}
|
|
95
|
+
scheduleFlush(delayMs) {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
if (this.timer || this.closed)
|
|
98
|
+
return;
|
|
99
|
+
this.timer = setTimeout(() => {
|
|
100
|
+
this.timer = null;
|
|
101
|
+
void this.flush();
|
|
102
|
+
}, delayMs);
|
|
103
|
+
(_b = (_a = this.timer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
104
|
+
}
|
|
105
|
+
export() {
|
|
106
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
+
// The graph must reach the server before any events that reference it.
|
|
108
|
+
if (this.graph && !this.graphSent) {
|
|
109
|
+
if ((yield this.post('/v1/graph', this.graph)) !== 'ok') {
|
|
110
|
+
this.retryLater();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
this.graphSent = true;
|
|
114
|
+
}
|
|
115
|
+
let reRegistrations = 0;
|
|
116
|
+
while (this.queue.length > 0) {
|
|
117
|
+
const batch = this.queue.slice(0, this.maxBatchSize);
|
|
118
|
+
const result = yield this.post('/v1/events', { events: batch });
|
|
119
|
+
// A restarted server lost the graph — re-register and resend the batch.
|
|
120
|
+
if (result === 'graph-required' && this.graph && reRegistrations < 3) {
|
|
121
|
+
reRegistrations += 1;
|
|
122
|
+
this.graphSent = false;
|
|
123
|
+
if ((yield this.post('/v1/graph', this.graph)) !== 'ok') {
|
|
124
|
+
this.retryLater();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.graphSent = true;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (result !== 'ok') {
|
|
131
|
+
this.retryLater();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
this.queue.splice(0, batch.length);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/** After a failed export, retry even if no new events arrive. */
|
|
139
|
+
retryLater() {
|
|
140
|
+
if (this.queue.length > 0 || (this.graph && !this.graphSent)) {
|
|
141
|
+
this.scheduleFlush(Math.max(this.flushIntervalMs, 2000));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
post(path, body) {
|
|
145
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
146
|
+
try {
|
|
147
|
+
const response = yield fetch(this.url + path, {
|
|
148
|
+
method: 'POST',
|
|
149
|
+
headers: { 'content-type': 'application/json' },
|
|
150
|
+
body: JSON.stringify(body),
|
|
151
|
+
});
|
|
152
|
+
if (response.status === 409)
|
|
153
|
+
return 'graph-required';
|
|
154
|
+
if (!response.ok) {
|
|
155
|
+
throw new Error(`server responded ${response.status}`);
|
|
156
|
+
}
|
|
157
|
+
this.warned = false;
|
|
158
|
+
return 'ok';
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
this.onError(error instanceof Error ? error : new Error(String(error)));
|
|
162
|
+
return 'failed';
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.DashboardClient = DashboardClient;
|
|
168
|
+
//# sourceMappingURL=dashboardClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboardClient.js","sourceRoot":"","sources":["../src/dashboardClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DisposeContext, EventSpan, InitializeContext, MethodCallContext, ServiceEventListener } from '@composed-di/core';
|
|
2
|
+
import { SpanEvent } from './events';
|
|
3
|
+
/**
|
|
4
|
+
* A ServiceEventListener that turns service events into structured
|
|
5
|
+
* start/end span events for the realtime dashboard.
|
|
6
|
+
*
|
|
7
|
+
* - Uses AsyncLocalStorage to link spans to the span that was active when
|
|
8
|
+
* they started, which lets the dashboard draw cross-service call edges
|
|
9
|
+
* (e.g. UserService.getUser -> Database.query). Because a listener does
|
|
10
|
+
* not control the invocation of the operation it observes, the context
|
|
11
|
+
* is entered with `enterWith` and can outlive the span within the same
|
|
12
|
+
* synchronous frame; the dashboard tolerates this, as parents are only
|
|
13
|
+
* resolved among still-open spans.
|
|
14
|
+
* - Emits events synchronously to subscribers; it never buffers.
|
|
15
|
+
*/
|
|
16
|
+
export declare class DashboardEventListener implements ServiceEventListener {
|
|
17
|
+
private readonly context;
|
|
18
|
+
private readonly listeners;
|
|
19
|
+
private nextId;
|
|
20
|
+
/**
|
|
21
|
+
* Subscribes to span events.
|
|
22
|
+
*
|
|
23
|
+
* @returns A function that removes the subscription.
|
|
24
|
+
*/
|
|
25
|
+
subscribe(listener: (event: SpanEvent) => void): () => void;
|
|
26
|
+
onInitialize({ key }: InitializeContext): EventSpan;
|
|
27
|
+
onDispose({ key }: DisposeContext): EventSpan;
|
|
28
|
+
onMethodCall({ key, methodName }: MethodCallContext): EventSpan;
|
|
29
|
+
private startSpan;
|
|
30
|
+
private emit;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=dashboardEventListener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboardEventListener.d.ts","sourceRoot":"","sources":["../src/dashboardEventListener.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAY,MAAM,UAAU,CAAC;AAO/C;;;;;;;;;;;;GAYG;AACH,qBAAa,sBAAuB,YAAW,oBAAoB;IACjE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyC;IACnE,OAAO,CAAC,MAAM,CAAK;IAEnB;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,IAAI;IAK3D,YAAY,CAAC,EAAE,GAAG,EAAE,EAAE,iBAAiB,GAAG,SAAS;IAInD,SAAS,CAAC,EAAE,GAAG,EAAE,EAAE,cAAc,GAAG,SAAS;IAI7C,YAAY,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,iBAAiB,GAAG,SAAS;IAI/D,OAAO,CAAC,SAAS;IAwCjB,OAAO,CAAC,IAAI;CAGb"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DashboardEventListener = void 0;
|
|
4
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
5
|
+
const node_perf_hooks_1 = require("node:perf_hooks");
|
|
6
|
+
/**
|
|
7
|
+
* A ServiceEventListener that turns service events into structured
|
|
8
|
+
* start/end span events for the realtime dashboard.
|
|
9
|
+
*
|
|
10
|
+
* - Uses AsyncLocalStorage to link spans to the span that was active when
|
|
11
|
+
* they started, which lets the dashboard draw cross-service call edges
|
|
12
|
+
* (e.g. UserService.getUser -> Database.query). Because a listener does
|
|
13
|
+
* not control the invocation of the operation it observes, the context
|
|
14
|
+
* is entered with `enterWith` and can outlive the span within the same
|
|
15
|
+
* synchronous frame; the dashboard tolerates this, as parents are only
|
|
16
|
+
* resolved among still-open spans.
|
|
17
|
+
* - Emits events synchronously to subscribers; it never buffers.
|
|
18
|
+
*/
|
|
19
|
+
class DashboardEventListener {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.context = new node_async_hooks_1.AsyncLocalStorage();
|
|
22
|
+
this.listeners = new Set();
|
|
23
|
+
this.nextId = 1;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Subscribes to span events.
|
|
27
|
+
*
|
|
28
|
+
* @returns A function that removes the subscription.
|
|
29
|
+
*/
|
|
30
|
+
subscribe(listener) {
|
|
31
|
+
this.listeners.add(listener);
|
|
32
|
+
return () => this.listeners.delete(listener);
|
|
33
|
+
}
|
|
34
|
+
onInitialize({ key }) {
|
|
35
|
+
return this.startSpan(key.name, 'initialize', 'initialize');
|
|
36
|
+
}
|
|
37
|
+
onDispose({ key }) {
|
|
38
|
+
return this.startSpan(key.name, 'dispose', 'dispose');
|
|
39
|
+
}
|
|
40
|
+
onMethodCall({ key, methodName }) {
|
|
41
|
+
return this.startSpan(key.name, methodName, 'call');
|
|
42
|
+
}
|
|
43
|
+
startSpan(service, method, kind) {
|
|
44
|
+
var _a;
|
|
45
|
+
const id = this.nextId++;
|
|
46
|
+
const parent = this.context.getStore();
|
|
47
|
+
this.emit({
|
|
48
|
+
type: 'start',
|
|
49
|
+
id,
|
|
50
|
+
parentId: (_a = parent === null || parent === void 0 ? void 0 : parent.id) !== null && _a !== void 0 ? _a : null,
|
|
51
|
+
name: `${service}.${method}`,
|
|
52
|
+
service,
|
|
53
|
+
method,
|
|
54
|
+
kind,
|
|
55
|
+
time: Date.now(),
|
|
56
|
+
});
|
|
57
|
+
const startedAt = node_perf_hooks_1.performance.now();
|
|
58
|
+
let ended = false;
|
|
59
|
+
const end = (error) => {
|
|
60
|
+
if (ended)
|
|
61
|
+
return;
|
|
62
|
+
ended = true;
|
|
63
|
+
this.emit({
|
|
64
|
+
type: 'end',
|
|
65
|
+
id,
|
|
66
|
+
time: Date.now(),
|
|
67
|
+
durationMs: node_perf_hooks_1.performance.now() - startedAt,
|
|
68
|
+
error,
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
// The observed operation runs right after this hook returns, in the
|
|
72
|
+
// same synchronous frame, so entering the context here makes this span
|
|
73
|
+
// the parent of any spans started inside the operation.
|
|
74
|
+
this.context.enterWith({ id });
|
|
75
|
+
return {
|
|
76
|
+
end: () => end(null),
|
|
77
|
+
error: (error) => end(errorMessage(error)),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
emit(event) {
|
|
81
|
+
this.listeners.forEach((listener) => listener(event));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.DashboardEventListener = DashboardEventListener;
|
|
85
|
+
function errorMessage(error) {
|
|
86
|
+
return error instanceof Error ? error.message : String(error);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=dashboardEventListener.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboardEventListener.js","sourceRoot":"","sources":["../src/dashboardEventListener.ts"],"names":[],"mappings":";;;AAAA,uDAAqD;AACrD,qDAA8C;AAe9C;;;;;;;;;;;;GAYG;AACH,MAAa,sBAAsB;IAAnC;QACmB,YAAO,GAAG,IAAI,oCAAiB,EAAe,CAAC;QAC/C,cAAS,GAAG,IAAI,GAAG,EAA8B,CAAC;QAC3D,WAAM,GAAG,CAAC,CAAC;IAmErB,CAAC;IAjEC;;;;OAIG;IACH,SAAS,CAAC,QAAoC;QAC5C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,YAAY,CAAC,EAAE,GAAG,EAAqB;QACrC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;IAC9D,CAAC;IAED,SAAS,CAAC,EAAE,GAAG,EAAkB;QAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC;IAED,YAAY,CAAC,EAAE,GAAG,EAAE,UAAU,EAAqB;QACjD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;IAEO,SAAS,CAAC,OAAe,EAAE,MAAc,EAAE,IAAc;;QAC/D,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QAEvC,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,OAAO;YACb,EAAE;YACF,QAAQ,EAAE,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,EAAE,mCAAI,IAAI;YAC5B,IAAI,EAAE,GAAG,OAAO,IAAI,MAAM,EAAE;YAC5B,OAAO;YACP,MAAM;YACN,IAAI;YACJ,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;SACjB,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,6BAAW,CAAC,GAAG,EAAE,CAAC;QACpC,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,MAAM,GAAG,GAAG,CAAC,KAAoB,EAAE,EAAE;YACnC,IAAI,KAAK;gBAAE,OAAO;YAClB,KAAK,GAAG,IAAI,CAAC;YACb,IAAI,CAAC,IAAI,CAAC;gBACR,IAAI,EAAE,KAAK;gBACX,EAAE;gBACF,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;gBAChB,UAAU,EAAE,6BAAW,CAAC,GAAG,EAAE,GAAG,SAAS;gBACzC,KAAK;aACN,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,oEAAoE;QACpE,uEAAuE;QACvE,wDAAwD;QACxD,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAE/B,OAAO;YACL,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;YACpB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;SAC3C,CAAC;IACJ,CAAC;IAEO,IAAI,CAAC,KAAgB;QAC3B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACxD,CAAC;CACF;AAtED,wDAsEC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The dashboard page, served at "/". Self-contained: no build step, no CDN.
|
|
3
|
+
*
|
|
4
|
+
* Connects to "/events" (Server-Sent Events), receives a full snapshot, then
|
|
5
|
+
* live span events. Renders the dependency graph as SVG (services laid out in
|
|
6
|
+
* dependency ranks, dependencies on the left), a stat-tile row, a services
|
|
7
|
+
* table, and an event log. Service state is shown as a status glyph + word,
|
|
8
|
+
* never color alone.
|
|
9
|
+
*/
|
|
10
|
+
export declare function renderDashboardHtml(): string;
|
|
11
|
+
//# sourceMappingURL=dashboardHtml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboardHtml.d.ts","sourceRoot":"","sources":["../src/dashboardHtml.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
|