@comprehend/telemetry-node 0.1.4 → 0.2.1
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 +112 -27
- package/dist/ComprehendDevSpanProcessor.d.ts +10 -6
- package/dist/ComprehendDevSpanProcessor.js +154 -87
- package/dist/ComprehendDevSpanProcessor.test.js +270 -449
- package/dist/ComprehendMetricsExporter.d.ts +18 -0
- package/dist/ComprehendMetricsExporter.js +178 -0
- package/dist/ComprehendMetricsExporter.test.d.ts +1 -0
- package/dist/ComprehendMetricsExporter.test.js +266 -0
- package/dist/ComprehendSDK.d.ts +18 -0
- package/dist/ComprehendSDK.js +56 -0
- package/dist/ComprehendSDK.test.d.ts +1 -0
- package/dist/ComprehendSDK.test.js +126 -0
- package/dist/WebSocketConnection.d.ts +23 -3
- package/dist/WebSocketConnection.js +106 -12
- package/dist/WebSocketConnection.test.js +236 -169
- package/dist/index.d.ts +3 -1
- package/dist/index.js +5 -1
- package/dist/util.d.ts +2 -0
- package/dist/util.js +7 -0
- package/dist/wire-protocol.d.ts +168 -28
- package/package.json +3 -1
- package/src/ComprehendDevSpanProcessor.test.ts +311 -507
- package/src/ComprehendDevSpanProcessor.ts +178 -105
- package/src/ComprehendMetricsExporter.test.ts +334 -0
- package/src/ComprehendMetricsExporter.ts +225 -0
- package/src/ComprehendSDK.test.ts +160 -0
- package/src/ComprehendSDK.ts +63 -0
- package/src/WebSocketConnection.test.ts +286 -205
- package/src/WebSocketConnection.ts +135 -13
- package/src/index.ts +3 -2
- package/src/util.ts +6 -0
- package/src/wire-protocol.ts +204 -29
- package/src/sql-analyzer.test.ts +0 -599
- package/src/sql-analyzer.ts +0 -439
|
@@ -1,15 +1,33 @@
|
|
|
1
|
-
import { ObservationInputMessage } from './wire-protocol';
|
|
1
|
+
import { AttributeType, CustomMetricSpecification, ObservationInputMessage, InitAck } from './wire-protocol';
|
|
2
2
|
export declare class WebSocketConnection {
|
|
3
3
|
private readonly organization;
|
|
4
4
|
private readonly token;
|
|
5
5
|
private readonly logger?;
|
|
6
|
+
private readonly onAuthorized?;
|
|
7
|
+
private readonly onCustomMetricChange?;
|
|
6
8
|
private readonly unacknowledgedObserved;
|
|
7
|
-
private readonly
|
|
9
|
+
private readonly seqQueues;
|
|
10
|
+
private readonly observationsQueue;
|
|
11
|
+
private readonly timeseriesQueue;
|
|
12
|
+
private readonly cumulativeQueue;
|
|
13
|
+
private readonly traceSpansQueue;
|
|
14
|
+
private readonly dbQueryQueue;
|
|
15
|
+
private readonly contextQueue;
|
|
8
16
|
private socket;
|
|
9
17
|
private reconnectDelay;
|
|
10
18
|
private shouldReconnect;
|
|
11
19
|
private authorized;
|
|
12
|
-
|
|
20
|
+
private processContext;
|
|
21
|
+
private ingestionId;
|
|
22
|
+
private _seq;
|
|
23
|
+
constructor(options: {
|
|
24
|
+
organization: string;
|
|
25
|
+
token: string;
|
|
26
|
+
logger?: (message: string) => void;
|
|
27
|
+
onAuthorized?: (ack: InitAck) => void;
|
|
28
|
+
onCustomMetricChange?: (specs: CustomMetricSpecification[]) => void;
|
|
29
|
+
});
|
|
30
|
+
nextSeq(): number;
|
|
13
31
|
private log;
|
|
14
32
|
private connect;
|
|
15
33
|
private onOpen;
|
|
@@ -17,6 +35,8 @@ export declare class WebSocketConnection {
|
|
|
17
35
|
private onClose;
|
|
18
36
|
private onError;
|
|
19
37
|
private sendRaw;
|
|
38
|
+
private sendContextStart;
|
|
39
|
+
setProcessContext(serviceEntityHash: string, resources: Record<string, AttributeType>): void;
|
|
20
40
|
sendMessage(message: ObservationInputMessage): void;
|
|
21
41
|
close(): void;
|
|
22
42
|
}
|
|
@@ -5,20 +5,57 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.WebSocketConnection = void 0;
|
|
7
7
|
const ws_1 = __importDefault(require("ws"));
|
|
8
|
-
const
|
|
8
|
+
const crypto_1 = require("crypto");
|
|
9
|
+
const util_1 = require("./util");
|
|
10
|
+
const INGESTION_ENDPOINT = process.env.COMPREHEND_INGESTION_ENDPOINT || 'wss://ingestion.comprehend.dev';
|
|
11
|
+
/** A queue of unacknowledged messages keyed by sequence number, with an associated ack type. */
|
|
12
|
+
class SeqQueue {
|
|
13
|
+
constructor(ackType) {
|
|
14
|
+
this.pending = new Map();
|
|
15
|
+
this.ackType = ackType;
|
|
16
|
+
}
|
|
17
|
+
add(message) {
|
|
18
|
+
this.pending.set(message.seq, message);
|
|
19
|
+
}
|
|
20
|
+
ack(seq) {
|
|
21
|
+
this.pending.delete(seq);
|
|
22
|
+
}
|
|
23
|
+
values() {
|
|
24
|
+
return this.pending.values();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
9
27
|
class WebSocketConnection {
|
|
10
|
-
constructor(
|
|
28
|
+
constructor(options) {
|
|
11
29
|
this.unacknowledgedObserved = new Map();
|
|
12
|
-
this.
|
|
30
|
+
this.observationsQueue = new SeqQueue('ack-observations');
|
|
31
|
+
this.timeseriesQueue = new SeqQueue('ack-timeseries');
|
|
32
|
+
this.cumulativeQueue = new SeqQueue('ack-cumulative');
|
|
33
|
+
this.traceSpansQueue = new SeqQueue('ack-tracespans');
|
|
34
|
+
this.dbQueryQueue = new SeqQueue('ack-db-query');
|
|
35
|
+
this.contextQueue = new SeqQueue('ack-context');
|
|
13
36
|
this.socket = null;
|
|
14
37
|
this.reconnectDelay = 1000;
|
|
15
38
|
this.shouldReconnect = true;
|
|
16
39
|
this.authorized = false;
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
40
|
+
this.processContext = null;
|
|
41
|
+
this.ingestionId = (0, crypto_1.randomUUID)();
|
|
42
|
+
this._seq = 1;
|
|
43
|
+
this.organization = options.organization;
|
|
44
|
+
this.token = options.token;
|
|
45
|
+
this.logger = options.logger;
|
|
46
|
+
this.onAuthorized = options.onAuthorized;
|
|
47
|
+
this.onCustomMetricChange = options.onCustomMetricChange;
|
|
48
|
+
// Build a lookup from ack type to queue for dispatch in onMessage
|
|
49
|
+
this.seqQueues = {};
|
|
50
|
+
for (const q of [this.observationsQueue, this.timeseriesQueue, this.cumulativeQueue,
|
|
51
|
+
this.traceSpansQueue, this.dbQueryQueue, this.contextQueue]) {
|
|
52
|
+
this.seqQueues[q.ackType] = q;
|
|
53
|
+
}
|
|
20
54
|
this.connect();
|
|
21
55
|
}
|
|
56
|
+
nextSeq() {
|
|
57
|
+
return this._seq++;
|
|
58
|
+
}
|
|
22
59
|
log(message) {
|
|
23
60
|
if (this.logger) {
|
|
24
61
|
this.logger(message);
|
|
@@ -35,9 +72,10 @@ class WebSocketConnection {
|
|
|
35
72
|
}
|
|
36
73
|
onOpen() {
|
|
37
74
|
this.log('WebSocket connected. Sending init/auth message.');
|
|
75
|
+
this.ingestionId = (0, crypto_1.randomUUID)();
|
|
38
76
|
const init = {
|
|
39
77
|
event: 'init',
|
|
40
|
-
protocolVersion:
|
|
78
|
+
protocolVersion: 2,
|
|
41
79
|
token: this.token,
|
|
42
80
|
};
|
|
43
81
|
this.sendRaw(init);
|
|
@@ -48,18 +86,40 @@ class WebSocketConnection {
|
|
|
48
86
|
if (msg.type === 'ack-authorized') {
|
|
49
87
|
this.authorized = true;
|
|
50
88
|
this.log('Authorization acknowledged by server.');
|
|
89
|
+
if (this.onAuthorized) {
|
|
90
|
+
this.onAuthorized(msg);
|
|
91
|
+
}
|
|
92
|
+
// Send context first if we have one
|
|
93
|
+
if (this.processContext) {
|
|
94
|
+
this.sendContextStart();
|
|
95
|
+
}
|
|
96
|
+
// Replay entities and interactions
|
|
51
97
|
for (const message of this.unacknowledgedObserved.values()) {
|
|
52
98
|
this.sendRaw(message);
|
|
53
99
|
}
|
|
54
|
-
|
|
55
|
-
|
|
100
|
+
// Replay all seq-based queues
|
|
101
|
+
for (const q of Object.values(this.seqQueues)) {
|
|
102
|
+
if (q === this.contextQueue)
|
|
103
|
+
continue; // already sent above
|
|
104
|
+
for (const message of q.values()) {
|
|
105
|
+
this.sendRaw(message);
|
|
106
|
+
}
|
|
56
107
|
}
|
|
57
108
|
}
|
|
58
109
|
else if (msg.type === 'ack-observed') {
|
|
59
110
|
this.unacknowledgedObserved.delete(msg.hash);
|
|
60
111
|
}
|
|
61
|
-
else if (msg.type === '
|
|
62
|
-
this.
|
|
112
|
+
else if (msg.type === 'custom-metric-change') {
|
|
113
|
+
if (this.onCustomMetricChange) {
|
|
114
|
+
this.onCustomMetricChange(msg.customMetrics);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if ('seq' in msg) {
|
|
118
|
+
// Dispatch seq-based acks to the appropriate queue
|
|
119
|
+
const queue = this.seqQueues[msg.type];
|
|
120
|
+
if (queue) {
|
|
121
|
+
queue.ack(msg.seq);
|
|
122
|
+
}
|
|
63
123
|
}
|
|
64
124
|
}
|
|
65
125
|
catch (e) {
|
|
@@ -81,12 +141,46 @@ class WebSocketConnection {
|
|
|
81
141
|
this.socket.send(JSON.stringify(message));
|
|
82
142
|
}
|
|
83
143
|
}
|
|
144
|
+
sendContextStart() {
|
|
145
|
+
if (!this.processContext)
|
|
146
|
+
return;
|
|
147
|
+
const seq = this.nextSeq();
|
|
148
|
+
const contextMsg = {
|
|
149
|
+
event: 'context-start',
|
|
150
|
+
seq,
|
|
151
|
+
timestamp: (0, util_1.hrTimeNow)(),
|
|
152
|
+
ingestionId: this.ingestionId,
|
|
153
|
+
type: 'process',
|
|
154
|
+
serviceEntityHash: this.processContext.serviceEntityHash,
|
|
155
|
+
resources: this.processContext.resources,
|
|
156
|
+
};
|
|
157
|
+
this.contextQueue.add(contextMsg);
|
|
158
|
+
this.sendRaw(contextMsg);
|
|
159
|
+
}
|
|
160
|
+
setProcessContext(serviceEntityHash, resources) {
|
|
161
|
+
this.processContext = { serviceEntityHash, resources };
|
|
162
|
+
if (this.authorized) {
|
|
163
|
+
this.sendContextStart();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
84
166
|
sendMessage(message) {
|
|
85
167
|
if (message.event === 'new-entity' || message.event === 'new-interaction') {
|
|
86
168
|
this.unacknowledgedObserved.set(message.hash, message);
|
|
87
169
|
}
|
|
88
170
|
else if (message.event === 'observations') {
|
|
89
|
-
this.
|
|
171
|
+
this.observationsQueue.add(message);
|
|
172
|
+
}
|
|
173
|
+
else if (message.event === 'timeseries') {
|
|
174
|
+
this.timeseriesQueue.add(message);
|
|
175
|
+
}
|
|
176
|
+
else if (message.event === 'cumulative') {
|
|
177
|
+
this.cumulativeQueue.add(message);
|
|
178
|
+
}
|
|
179
|
+
else if (message.event === 'tracespans') {
|
|
180
|
+
this.traceSpansQueue.add(message);
|
|
181
|
+
}
|
|
182
|
+
else if (message.event === 'db-query') {
|
|
183
|
+
this.dbQueryQueue.add(message);
|
|
90
184
|
}
|
|
91
185
|
if (this.authorized) {
|
|
92
186
|
this.sendRaw(message);
|