@principal-ai/otel-collector-server 0.1.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/README.md +252 -0
- package/dist/OTELCollectorServer.d.ts +52 -0
- package/dist/OTELCollectorServer.d.ts.map +1 -0
- package/dist/OTELCollectorServer.js +252 -0
- package/dist/OTELCollectorServer.js.map +1 -0
- package/dist/__tests__/fixtures/traces.d.ts +8 -0
- package/dist/__tests__/fixtures/traces.d.ts.map +1 -0
- package/dist/__tests__/fixtures/traces.js +186 -0
- package/dist/__tests__/fixtures/traces.js.map +1 -0
- package/dist/bin/otel-collector-server.d.ts +6 -0
- package/dist/bin/otel-collector-server.d.ts.map +1 -0
- package/dist/bin/otel-collector-server.js +132 -0
- package/dist/bin/otel-collector-server.js.map +1 -0
- package/dist/core/BinaryManager.d.ts +35 -0
- package/dist/core/BinaryManager.d.ts.map +1 -0
- package/dist/core/BinaryManager.js +143 -0
- package/dist/core/BinaryManager.js.map +1 -0
- package/dist/core/CollectorProcessManager.d.ts +60 -0
- package/dist/core/CollectorProcessManager.d.ts.map +1 -0
- package/dist/core/CollectorProcessManager.js +197 -0
- package/dist/core/CollectorProcessManager.js.map +1 -0
- package/dist/core/ConfigGenerator.d.ts +23 -0
- package/dist/core/ConfigGenerator.d.ts.map +1 -0
- package/dist/core/ConfigGenerator.js +115 -0
- package/dist/core/ConfigGenerator.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/output/ConsoleOutput.d.ts +24 -0
- package/dist/output/ConsoleOutput.d.ts.map +1 -0
- package/dist/output/ConsoleOutput.js +156 -0
- package/dist/output/ConsoleOutput.js.map +1 -0
- package/dist/output/FileOutput.d.ts +18 -0
- package/dist/output/FileOutput.d.ts.map +1 -0
- package/dist/output/FileOutput.js +88 -0
- package/dist/output/FileOutput.js.map +1 -0
- package/dist/output/MessagePortOutput.d.ts +19 -0
- package/dist/output/MessagePortOutput.d.ts.map +1 -0
- package/dist/output/MessagePortOutput.js +25 -0
- package/dist/output/MessagePortOutput.js.map +1 -0
- package/dist/output/TraceOutput.d.ts +13 -0
- package/dist/output/TraceOutput.d.ts.map +1 -0
- package/dist/output/TraceOutput.js +6 -0
- package/dist/output/TraceOutput.js.map +1 -0
- package/dist/router/PortRouter.d.ts +41 -0
- package/dist/router/PortRouter.d.ts.map +1 -0
- package/dist/router/PortRouter.js +130 -0
- package/dist/router/PortRouter.js.map +1 -0
- package/dist/server/OTLPForwardingServer.d.ts +59 -0
- package/dist/server/OTLPForwardingServer.d.ts.map +1 -0
- package/dist/server/OTLPForwardingServer.js +245 -0
- package/dist/server/OTLPForwardingServer.js.map +1 -0
- package/dist/shared/logger.d.ts +18 -0
- package/dist/shared/logger.d.ts.map +1 -0
- package/dist/shared/logger.js +59 -0
- package/dist/shared/logger.js.map +1 -0
- package/dist/shared/types.d.ts +47 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +6 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* FileOutput - Write traces to file as JSONL
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.FileOutput = void 0;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const logger_1 = require("../shared/logger");
|
|
42
|
+
class FileOutput {
|
|
43
|
+
constructor(filePath, logger) {
|
|
44
|
+
this.closed = false;
|
|
45
|
+
this.logger = logger || (0, logger_1.createLogger)('FileOutput');
|
|
46
|
+
// Create write stream
|
|
47
|
+
this.writeStream = fs.createWriteStream(filePath, {
|
|
48
|
+
flags: 'a', // Append mode
|
|
49
|
+
encoding: 'utf-8',
|
|
50
|
+
});
|
|
51
|
+
this.writeStream.on('error', (err) => {
|
|
52
|
+
this.logger.error('File write error:', err);
|
|
53
|
+
});
|
|
54
|
+
this.logger.info(`Writing traces to: ${filePath}`);
|
|
55
|
+
}
|
|
56
|
+
send(payload, source) {
|
|
57
|
+
const line = JSON.stringify({
|
|
58
|
+
timestamp: new Date().toISOString(),
|
|
59
|
+
source,
|
|
60
|
+
payload,
|
|
61
|
+
});
|
|
62
|
+
this.writeStream.write(line + '\n');
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Close the file stream
|
|
66
|
+
*/
|
|
67
|
+
close() {
|
|
68
|
+
if (this.closed) {
|
|
69
|
+
this.logger.debug('File stream already closed');
|
|
70
|
+
return Promise.resolve();
|
|
71
|
+
}
|
|
72
|
+
this.closed = true;
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
this.writeStream.end((err) => {
|
|
75
|
+
if (err) {
|
|
76
|
+
this.logger.error('Error closing file stream:', err);
|
|
77
|
+
reject(err);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.logger.info('File stream closed');
|
|
81
|
+
resolve();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.FileOutput = FileOutput;
|
|
88
|
+
//# sourceMappingURL=FileOutput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileOutput.js","sourceRoot":"","sources":["../../src/output/FileOutput.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,uCAAyB;AAGzB,6CAAwD;AAExD,MAAa,UAAU;IAKrB,YAAY,QAAgB,EAAE,MAAe;QAFrC,WAAM,GAAY,KAAK,CAAC;QAG9B,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,IAAA,qBAAY,EAAC,YAAY,CAAC,CAAC;QAEnD,sBAAsB;QACtB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE;YAChD,KAAK,EAAE,GAAG,EAAE,cAAc;YAC1B,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,sBAAsB,QAAQ,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,CAAC,OAAmC,EAAE,MAAc;QACtD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM;YACN,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,GAAsB,EAAE,EAAE;gBAC9C,IAAI,GAAG,EAAE,CAAC;oBACR,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;oBACrD,MAAM,CAAC,GAAG,CAAC,CAAC;gBACd,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;oBACvC,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AArDD,gCAqDC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MessagePortOutput - Output traces via MessagePort for Electron renderer windows
|
|
3
|
+
*/
|
|
4
|
+
import { TraceOutput } from './TraceOutput';
|
|
5
|
+
import { PortRouter } from '../router/PortRouter';
|
|
6
|
+
import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer';
|
|
7
|
+
export declare class MessagePortOutput implements TraceOutput {
|
|
8
|
+
private router;
|
|
9
|
+
constructor(router: PortRouter);
|
|
10
|
+
/**
|
|
11
|
+
* Send trace payload to registered windows via MessagePort
|
|
12
|
+
*/
|
|
13
|
+
send(payload: IExportTraceServiceRequest, source: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Get the underlying router for registration management
|
|
16
|
+
*/
|
|
17
|
+
getRouter(): PortRouter;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=MessagePortOutput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessagePortOutput.d.ts","sourceRoot":"","sources":["../../src/output/MessagePortOutput.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAE7E,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,EAAE,UAAU;IAI9B;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,0BAA0B,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/D;;OAEG;IACH,SAAS,IAAI,UAAU;CAGxB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MessagePortOutput - Output traces via MessagePort for Electron renderer windows
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MessagePortOutput = void 0;
|
|
7
|
+
class MessagePortOutput {
|
|
8
|
+
constructor(router) {
|
|
9
|
+
this.router = router;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Send trace payload to registered windows via MessagePort
|
|
13
|
+
*/
|
|
14
|
+
send(payload, source) {
|
|
15
|
+
this.router.routePayload(payload, source);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get the underlying router for registration management
|
|
19
|
+
*/
|
|
20
|
+
getRouter() {
|
|
21
|
+
return this.router;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.MessagePortOutput = MessagePortOutput;
|
|
25
|
+
//# sourceMappingURL=MessagePortOutput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessagePortOutput.js","sourceRoot":"","sources":["../../src/output/MessagePortOutput.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAMH,MAAa,iBAAiB;IAG5B,YAAY,MAAkB;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,OAAmC,EAAE,MAAc;QACtD,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AApBD,8CAoBC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TraceOutput - Abstract interface for outputting traces
|
|
3
|
+
*/
|
|
4
|
+
import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer';
|
|
5
|
+
export interface TraceOutput {
|
|
6
|
+
/**
|
|
7
|
+
* Send traces to output destination
|
|
8
|
+
* @param payload - Raw OTLP trace payload
|
|
9
|
+
* @param source - Source URL the traces came from
|
|
10
|
+
*/
|
|
11
|
+
send(payload: IExportTraceServiceRequest, source: string): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=TraceOutput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TraceOutput.d.ts","sourceRoot":"","sources":["../../src/output/TraceOutput.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,0BAA0B,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACjE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TraceOutput.js","sourceRoot":"","sources":["../../src/output/TraceOutput.ts"],"names":[],"mappings":";AAAA;;GAEG"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PortRouter - Routes OTLP traces to registered renderer windows via MessagePort
|
|
3
|
+
*/
|
|
4
|
+
import { MessagePort } from 'worker_threads';
|
|
5
|
+
import { Logger } from '../shared/logger';
|
|
6
|
+
import { PortRegistration } from '../shared/types';
|
|
7
|
+
import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer';
|
|
8
|
+
export declare class PortRouter {
|
|
9
|
+
private logger;
|
|
10
|
+
private portRegistry;
|
|
11
|
+
constructor(logger?: Logger);
|
|
12
|
+
/**
|
|
13
|
+
* Register a MessagePort for a specific window and source URL
|
|
14
|
+
*/
|
|
15
|
+
registerPort(windowId: string, sourceUrl: string, port: MessagePort): void;
|
|
16
|
+
/**
|
|
17
|
+
* Unregister a MessagePort for a specific window and source URL
|
|
18
|
+
*/
|
|
19
|
+
unregisterPort(windowId: string, sourceUrl: string): void;
|
|
20
|
+
/**
|
|
21
|
+
* Unregister all MessagePorts for a specific window
|
|
22
|
+
*/
|
|
23
|
+
unregisterWindow(windowId: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Route OTLP payload to registered windows based on source URL
|
|
26
|
+
*/
|
|
27
|
+
routePayload(payload: IExportTraceServiceRequest, sourceUrl: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Get all active registrations
|
|
30
|
+
*/
|
|
31
|
+
getRegistrations(): Map<string, PortRegistration[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Get count of active registrations
|
|
34
|
+
*/
|
|
35
|
+
getRegistrationCount(): number;
|
|
36
|
+
/**
|
|
37
|
+
* Get all registered source URLs
|
|
38
|
+
*/
|
|
39
|
+
getRegisteredSources(): string[];
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=PortRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PortRouter.d.ts","sourceRoot":"","sources":["../../src/router/PortRouter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAgB,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAE7E,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAkC;gBAE1C,MAAM,CAAC,EAAE,MAAM;IAK3B;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI;IA0B1E;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAoBzD;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAuBxC;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,0BAA0B,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IA4B1E;;OAEG;IACH,gBAAgB,IAAI,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAInD;;OAEG;IACH,oBAAoB,IAAI,MAAM;IAQ9B;;OAEG;IACH,oBAAoB,IAAI,MAAM,EAAE;CAGjC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* PortRouter - Routes OTLP traces to registered renderer windows via MessagePort
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PortRouter = void 0;
|
|
7
|
+
const logger_1 = require("../shared/logger");
|
|
8
|
+
class PortRouter {
|
|
9
|
+
constructor(logger) {
|
|
10
|
+
this.logger = logger || (0, logger_1.createLogger)('PortRouter');
|
|
11
|
+
this.portRegistry = new Map();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Register a MessagePort for a specific window and source URL
|
|
15
|
+
*/
|
|
16
|
+
registerPort(windowId, sourceUrl, port) {
|
|
17
|
+
this.logger.info(`Registering port for window ${windowId}, source: ${sourceUrl}`);
|
|
18
|
+
const registration = {
|
|
19
|
+
windowId,
|
|
20
|
+
sourceUrl,
|
|
21
|
+
port,
|
|
22
|
+
registeredAt: Date.now(),
|
|
23
|
+
};
|
|
24
|
+
// Get or create registry for this source URL
|
|
25
|
+
const existing = this.portRegistry.get(sourceUrl) || [];
|
|
26
|
+
// Check if this window is already registered for this source
|
|
27
|
+
const existingIndex = existing.findIndex(r => r.windowId === windowId);
|
|
28
|
+
if (existingIndex >= 0) {
|
|
29
|
+
this.logger.warn(`Window ${windowId} already registered for ${sourceUrl}, replacing`);
|
|
30
|
+
existing[existingIndex] = registration;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
existing.push(registration);
|
|
34
|
+
}
|
|
35
|
+
this.portRegistry.set(sourceUrl, existing);
|
|
36
|
+
this.logger.debug(`Port registry now has ${existing.length} registrations for ${sourceUrl}`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Unregister a MessagePort for a specific window and source URL
|
|
40
|
+
*/
|
|
41
|
+
unregisterPort(windowId, sourceUrl) {
|
|
42
|
+
this.logger.info(`Unregistering port for window ${windowId}, source: ${sourceUrl}`);
|
|
43
|
+
const registrations = this.portRegistry.get(sourceUrl);
|
|
44
|
+
if (!registrations) {
|
|
45
|
+
this.logger.warn(`No registrations found for source: ${sourceUrl}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const filtered = registrations.filter(r => r.windowId !== windowId);
|
|
49
|
+
if (filtered.length === 0) {
|
|
50
|
+
this.portRegistry.delete(sourceUrl);
|
|
51
|
+
this.logger.debug(`Removed source ${sourceUrl} from registry (no more registrations)`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.portRegistry.set(sourceUrl, filtered);
|
|
55
|
+
this.logger.debug(`${filtered.length} registrations remaining for ${sourceUrl}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Unregister all MessagePorts for a specific window
|
|
60
|
+
*/
|
|
61
|
+
unregisterWindow(windowId) {
|
|
62
|
+
this.logger.info(`Unregistering all ports for window ${windowId}`);
|
|
63
|
+
let removedCount = 0;
|
|
64
|
+
const sourcesToRemove = [];
|
|
65
|
+
for (const [sourceUrl, registrations] of this.portRegistry.entries()) {
|
|
66
|
+
const filtered = registrations.filter(r => r.windowId !== windowId);
|
|
67
|
+
removedCount += registrations.length - filtered.length;
|
|
68
|
+
if (filtered.length === 0) {
|
|
69
|
+
sourcesToRemove.push(sourceUrl);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this.portRegistry.set(sourceUrl, filtered);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Remove sources with no registrations
|
|
76
|
+
sourcesToRemove.forEach(source => this.portRegistry.delete(source));
|
|
77
|
+
this.logger.info(`Unregistered ${removedCount} ports for window ${windowId}`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Route OTLP payload to registered windows based on source URL
|
|
81
|
+
*/
|
|
82
|
+
routePayload(payload, sourceUrl) {
|
|
83
|
+
const registrations = this.portRegistry.get(sourceUrl);
|
|
84
|
+
if (!registrations || registrations.length === 0) {
|
|
85
|
+
this.logger.debug(`No registrations for source: ${sourceUrl}, dropping traces`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.logger.debug(`Routing traces from ${sourceUrl} to ${registrations.length} window(s)`);
|
|
89
|
+
const message = {
|
|
90
|
+
type: 'TRACE_BATCH',
|
|
91
|
+
payload,
|
|
92
|
+
source: sourceUrl,
|
|
93
|
+
timestamp: Date.now(),
|
|
94
|
+
};
|
|
95
|
+
for (const registration of registrations) {
|
|
96
|
+
try {
|
|
97
|
+
registration.port.postMessage(message);
|
|
98
|
+
this.logger.debug(`Sent traces to window ${registration.windowId}`);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
this.logger.error(`Failed to send to window ${registration.windowId}:`, err);
|
|
102
|
+
// Consider auto-unregistering failed ports?
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get all active registrations
|
|
108
|
+
*/
|
|
109
|
+
getRegistrations() {
|
|
110
|
+
return new Map(this.portRegistry);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get count of active registrations
|
|
114
|
+
*/
|
|
115
|
+
getRegistrationCount() {
|
|
116
|
+
let count = 0;
|
|
117
|
+
for (const registrations of this.portRegistry.values()) {
|
|
118
|
+
count += registrations.length;
|
|
119
|
+
}
|
|
120
|
+
return count;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get all registered source URLs
|
|
124
|
+
*/
|
|
125
|
+
getRegisteredSources() {
|
|
126
|
+
return Array.from(this.portRegistry.keys());
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.PortRouter = PortRouter;
|
|
130
|
+
//# sourceMappingURL=PortRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PortRouter.js","sourceRoot":"","sources":["../../src/router/PortRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTLPForwardingServer - HTTP server that receives OTLP traces from Go collector
|
|
3
|
+
*/
|
|
4
|
+
import { TraceOutput } from '../output/TraceOutput';
|
|
5
|
+
import { Logger } from '../shared/logger';
|
|
6
|
+
export interface HTTPServerConfig {
|
|
7
|
+
port: number;
|
|
8
|
+
enableCORS?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare class OTLPForwardingServer {
|
|
11
|
+
private config;
|
|
12
|
+
private traceOutput;
|
|
13
|
+
private logger;
|
|
14
|
+
private server;
|
|
15
|
+
private port;
|
|
16
|
+
private tracesReceived;
|
|
17
|
+
constructor(config: HTTPServerConfig, traceOutput: TraceOutput, logger?: Logger);
|
|
18
|
+
/**
|
|
19
|
+
* Start the HTTP server
|
|
20
|
+
*/
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Stop the HTTP server
|
|
24
|
+
*/
|
|
25
|
+
stop(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Get the server port
|
|
28
|
+
*/
|
|
29
|
+
getPort(): number;
|
|
30
|
+
/**
|
|
31
|
+
* Get traces received count
|
|
32
|
+
*/
|
|
33
|
+
getTracesReceived(): number;
|
|
34
|
+
/**
|
|
35
|
+
* Handle incoming HTTP request
|
|
36
|
+
*/
|
|
37
|
+
private handleRequest;
|
|
38
|
+
/**
|
|
39
|
+
* Handle OTLP trace request - supports both JSON and protobuf formats
|
|
40
|
+
*/
|
|
41
|
+
private handleTraceRequest;
|
|
42
|
+
/**
|
|
43
|
+
* Handle health check request
|
|
44
|
+
*/
|
|
45
|
+
private handleHealthCheck;
|
|
46
|
+
/**
|
|
47
|
+
* Handle CORS headers
|
|
48
|
+
*/
|
|
49
|
+
private handleCORS;
|
|
50
|
+
/**
|
|
51
|
+
* Read request body as Buffer
|
|
52
|
+
*/
|
|
53
|
+
private readBody;
|
|
54
|
+
/**
|
|
55
|
+
* Extract source URL from OTLP payload
|
|
56
|
+
*/
|
|
57
|
+
private extractSourceUrl;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=OTLPForwardingServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OTLPForwardingServer.d.ts","sourceRoot":"","sources":["../../src/server/OTLPForwardingServer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAgB,MAAM,kBAAkB,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,qBAAa,oBAAoB;IAO7B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,WAAW;IAPrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,cAAc,CAAa;gBAGzB,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,WAAW,EAChC,MAAM,CAAC,EAAE,MAAM;IAMjB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB3B;;OAEG;IACH,OAAO,IAAI,MAAM;IAIjB;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;OAEG;YACW,kBAAkB;IA0DhC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAkBhB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAuBzB"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OTLPForwardingServer - HTTP server that receives OTLP traces from Go collector
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.OTLPForwardingServer = void 0;
|
|
40
|
+
const http = __importStar(require("http"));
|
|
41
|
+
const root = __importStar(require("@opentelemetry/otlp-transformer/build/esm/generated/root"));
|
|
42
|
+
const logger_1 = require("../shared/logger");
|
|
43
|
+
class OTLPForwardingServer {
|
|
44
|
+
constructor(config, traceOutput, logger) {
|
|
45
|
+
this.config = config;
|
|
46
|
+
this.traceOutput = traceOutput;
|
|
47
|
+
this.server = null;
|
|
48
|
+
this.tracesReceived = 0;
|
|
49
|
+
this.logger = logger || (0, logger_1.createLogger)('OTLPForwardingServer');
|
|
50
|
+
this.port = config.port;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Start the HTTP server
|
|
54
|
+
*/
|
|
55
|
+
async start() {
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
this.server = http.createServer((req, res) => {
|
|
58
|
+
this.handleRequest(req, res);
|
|
59
|
+
});
|
|
60
|
+
this.server.on('error', (err) => {
|
|
61
|
+
this.logger.error('Server error:', err);
|
|
62
|
+
reject(err);
|
|
63
|
+
});
|
|
64
|
+
this.server.listen(this.port, () => {
|
|
65
|
+
this.logger.info(`OTLP forwarding server listening on http://localhost:${this.port}`);
|
|
66
|
+
resolve();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Stop the HTTP server
|
|
72
|
+
*/
|
|
73
|
+
async stop() {
|
|
74
|
+
if (!this.server) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
this.server.close((err) => {
|
|
79
|
+
if (err) {
|
|
80
|
+
this.logger.error('Error stopping server:', err);
|
|
81
|
+
reject(err);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
this.logger.info('Server stopped');
|
|
85
|
+
this.server = null;
|
|
86
|
+
resolve();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the server port
|
|
93
|
+
*/
|
|
94
|
+
getPort() {
|
|
95
|
+
return this.port;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get traces received count
|
|
99
|
+
*/
|
|
100
|
+
getTracesReceived() {
|
|
101
|
+
return this.tracesReceived;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Handle incoming HTTP request
|
|
105
|
+
*/
|
|
106
|
+
handleRequest(req, res) {
|
|
107
|
+
// Handle CORS preflight
|
|
108
|
+
if (this.config.enableCORS && req.method === 'OPTIONS') {
|
|
109
|
+
this.handleCORS(req, res);
|
|
110
|
+
res.writeHead(204);
|
|
111
|
+
res.end();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Health check endpoint
|
|
115
|
+
if (req.url === '/health' && req.method === 'GET') {
|
|
116
|
+
this.handleHealthCheck(req, res);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// OTLP traces endpoint
|
|
120
|
+
if (req.url === '/v1/traces' && req.method === 'POST') {
|
|
121
|
+
// Handle async trace request - must use void to explicitly ignore promise
|
|
122
|
+
void this.handleTraceRequest(req, res);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Not found
|
|
126
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
127
|
+
res.end(JSON.stringify({ error: 'Not found' }));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Handle OTLP trace request - supports both JSON and protobuf formats
|
|
131
|
+
*/
|
|
132
|
+
async handleTraceRequest(req, res) {
|
|
133
|
+
try {
|
|
134
|
+
// Read body as buffer
|
|
135
|
+
const bodyBuffer = await this.readBody(req);
|
|
136
|
+
// Determine format from Content-Type header
|
|
137
|
+
const contentType = req.headers['content-type'] || 'application/json';
|
|
138
|
+
let payload;
|
|
139
|
+
if (contentType.includes('application/x-protobuf') || contentType.includes('application/octet-stream')) {
|
|
140
|
+
// Decode protobuf format
|
|
141
|
+
this.logger.debug('Decoding protobuf trace request');
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
143
|
+
const rootAny = root;
|
|
144
|
+
const traceRequestType = rootAny.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
|
|
145
|
+
const decoded = traceRequestType.decode(bodyBuffer);
|
|
146
|
+
payload = traceRequestType.toObject(decoded, {
|
|
147
|
+
longs: String,
|
|
148
|
+
enums: String,
|
|
149
|
+
bytes: String,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// Parse JSON format (default)
|
|
154
|
+
this.logger.debug('Parsing JSON trace request');
|
|
155
|
+
const bodyString = bodyBuffer.toString('utf-8');
|
|
156
|
+
payload = JSON.parse(bodyString);
|
|
157
|
+
}
|
|
158
|
+
// Extract source URL
|
|
159
|
+
const sourceUrl = this.extractSourceUrl(payload);
|
|
160
|
+
// Forward to output
|
|
161
|
+
this.traceOutput.send(payload, sourceUrl);
|
|
162
|
+
this.tracesReceived++;
|
|
163
|
+
// Send success response
|
|
164
|
+
this.handleCORS(req, res);
|
|
165
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
166
|
+
res.end(JSON.stringify({ status: 'ok' }));
|
|
167
|
+
this.logger.debug(`Received traces from ${sourceUrl}`);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
171
|
+
const errorStack = err instanceof Error ? err.stack : undefined;
|
|
172
|
+
this.logger.error('Error handling trace request:', errorMessage);
|
|
173
|
+
if (errorStack) {
|
|
174
|
+
this.logger.error('Stack trace:', errorStack);
|
|
175
|
+
}
|
|
176
|
+
if (!res.headersSent) {
|
|
177
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
178
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Handle health check request
|
|
184
|
+
*/
|
|
185
|
+
handleHealthCheck(req, res) {
|
|
186
|
+
this.handleCORS(req, res);
|
|
187
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
188
|
+
res.end(JSON.stringify({
|
|
189
|
+
status: 'healthy',
|
|
190
|
+
tracesReceived: this.tracesReceived,
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Handle CORS headers
|
|
195
|
+
*/
|
|
196
|
+
handleCORS(_req, res) {
|
|
197
|
+
if (!this.config.enableCORS) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
201
|
+
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
|
|
202
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Read request body as Buffer
|
|
206
|
+
*/
|
|
207
|
+
readBody(req) {
|
|
208
|
+
return new Promise((resolve, reject) => {
|
|
209
|
+
const chunks = [];
|
|
210
|
+
req.on('data', (chunk) => {
|
|
211
|
+
chunks.push(chunk);
|
|
212
|
+
});
|
|
213
|
+
req.on('end', () => {
|
|
214
|
+
resolve(Buffer.concat(chunks));
|
|
215
|
+
});
|
|
216
|
+
req.on('error', (err) => {
|
|
217
|
+
reject(err);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Extract source URL from OTLP payload
|
|
223
|
+
*/
|
|
224
|
+
extractSourceUrl(payload) {
|
|
225
|
+
// Try to extract from resource attributes
|
|
226
|
+
const resourceSpans = payload.resourceSpans?.[0];
|
|
227
|
+
if (!resourceSpans) {
|
|
228
|
+
return 'unknown';
|
|
229
|
+
}
|
|
230
|
+
const attributes = resourceSpans.resource?.attributes || [];
|
|
231
|
+
// Look for dev.server.url attribute
|
|
232
|
+
const devServerUrl = attributes.find((attr) => attr.key === 'dev.server.url');
|
|
233
|
+
if (devServerUrl?.value?.stringValue) {
|
|
234
|
+
return devServerUrl.value.stringValue;
|
|
235
|
+
}
|
|
236
|
+
// Fallback to service.name
|
|
237
|
+
const serviceName = attributes.find((attr) => attr.key === 'service.name');
|
|
238
|
+
if (serviceName?.value?.stringValue) {
|
|
239
|
+
return serviceName.value.stringValue;
|
|
240
|
+
}
|
|
241
|
+
return 'unknown';
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
exports.OTLPForwardingServer = OTLPForwardingServer;
|
|
245
|
+
//# sourceMappingURL=OTLPForwardingServer.js.map
|