@downtrace/protocol 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/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/index.d.ts +334 -0
- package/dist/index.js +339 -0
- package/package.json +50 -0
- package/schema/v0/aggregates.schema.json +220 -0
- package/schema/v0/fixtures/invalid/counts-length.json +45 -0
- package/schema/v0/fixtures/invalid/negative-count.json +45 -0
- package/schema/v0/fixtures/invalid/unknown-protocol.json +45 -0
- package/schema/v0/fixtures/valid/minimal.json +45 -0
- package/schema/v0/fixtures/valid/multi-route.json +102 -0
- package/schema/v0/fixtures/valid/six-intervals.json +170 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Raúl Jiménez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @downtrace/protocol
|
|
2
|
+
|
|
3
|
+
The ingestion contract between Downtrace agents and the Downtrace cloud, as a JSON Schema (draft 2020-12) plus the TypeScript types generated from it.
|
|
4
|
+
|
|
5
|
+
- `schema/v0/aggregates.schema.json` — the contract. Everything else derives from it.
|
|
6
|
+
- `schema/v0/fixtures/{valid,invalid}/` — examples every implementation must accept and reject.
|
|
7
|
+
- Exports: `PROTOCOL_VERSION`, `AGGREGATES_PATH`, `AGGREGATES_SCHEMA_V0`, `LATENCY_BOUNDARIES_V0`, `LATENCY_BUCKETS_V0`, `latencyBucket()`, and the types `AggregatesBatch`, `Interval`, `Endpoint`, `LatencyHistogram`, …
|
|
8
|
+
|
|
9
|
+
## v0 in one sentence
|
|
10
|
+
|
|
11
|
+
Every 10 seconds, for every route, an agent sends how many requests there were, how many failed, how statuses split, and a **35-bucket fixed latency histogram** (0.5 ms → 60 s). Fixed buckets add up across instances, so the cloud can compute fleet-wide percentiles.
|
|
12
|
+
|
|
13
|
+
`POST {DOWNTRACE_URL}/v0/aggregates` · `Authorization: Bearer <token>` · JSON · 202 accepted, 400 invalid, 401 bad token.
|
|
14
|
+
|
|
15
|
+
## Source
|
|
16
|
+
|
|
17
|
+
Developed in a monorepo and mirrored read-only to [RadW2020/downtrace-agent](https://github.com/RadW2020/downtrace-agent). MIT.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
//#region src/generated/aggregates.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A batch of per-interval, per-route aggregates sent by an agent to the cloud (POST /v0/aggregates).
|
|
4
|
+
*/
|
|
5
|
+
interface AggregatesBatch {
|
|
6
|
+
/**
|
|
7
|
+
* Protocol version this batch conforms to.
|
|
8
|
+
*/
|
|
9
|
+
protocol: "0.1.0";
|
|
10
|
+
agent: AgentInfo;
|
|
11
|
+
instance: InstanceInfo;
|
|
12
|
+
deploy: DeployInfo;
|
|
13
|
+
/**
|
|
14
|
+
* @minItems 1
|
|
15
|
+
* @maxItems 6
|
|
16
|
+
*/
|
|
17
|
+
intervals: [Interval] | [Interval, Interval] | [Interval, Interval, Interval] | [Interval, Interval, Interval, Interval] | [Interval, Interval, Interval, Interval, Interval] | [Interval, Interval, Interval, Interval, Interval, Interval];
|
|
18
|
+
}
|
|
19
|
+
interface AgentInfo {
|
|
20
|
+
name: string;
|
|
21
|
+
version: string;
|
|
22
|
+
runtime: "node" | "go";
|
|
23
|
+
runtimeVersion: string;
|
|
24
|
+
}
|
|
25
|
+
interface InstanceInfo {
|
|
26
|
+
/**
|
|
27
|
+
* Random identifier generated once per process.
|
|
28
|
+
*/
|
|
29
|
+
id: string;
|
|
30
|
+
hostname: string;
|
|
31
|
+
pid: number;
|
|
32
|
+
}
|
|
33
|
+
interface DeployInfo {
|
|
34
|
+
/**
|
|
35
|
+
* Deployed version or commit; "unknown" when undetectable.
|
|
36
|
+
*/
|
|
37
|
+
version: string;
|
|
38
|
+
environment: string;
|
|
39
|
+
}
|
|
40
|
+
interface Interval {
|
|
41
|
+
/**
|
|
42
|
+
* Interval start, Unix epoch milliseconds.
|
|
43
|
+
*/
|
|
44
|
+
start: number;
|
|
45
|
+
durationMs: number;
|
|
46
|
+
/**
|
|
47
|
+
* @maxItems 4096
|
|
48
|
+
*/
|
|
49
|
+
endpoints: Endpoint[];
|
|
50
|
+
}
|
|
51
|
+
interface Endpoint {
|
|
52
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | "OTHER";
|
|
53
|
+
/**
|
|
54
|
+
* Normalised route template, e.g. /products/:id, or (other).
|
|
55
|
+
*/
|
|
56
|
+
route: string;
|
|
57
|
+
count: number;
|
|
58
|
+
/**
|
|
59
|
+
* Responses with a 5xx status.
|
|
60
|
+
*/
|
|
61
|
+
errors: number;
|
|
62
|
+
status: StatusClasses;
|
|
63
|
+
latency: LatencyHistogram;
|
|
64
|
+
}
|
|
65
|
+
interface StatusClasses {
|
|
66
|
+
/**
|
|
67
|
+
* 2xx
|
|
68
|
+
*/
|
|
69
|
+
success: number;
|
|
70
|
+
/**
|
|
71
|
+
* 3xx
|
|
72
|
+
*/
|
|
73
|
+
redirect: number;
|
|
74
|
+
/**
|
|
75
|
+
* 4xx
|
|
76
|
+
*/
|
|
77
|
+
clientError: number;
|
|
78
|
+
/**
|
|
79
|
+
* 5xx
|
|
80
|
+
*/
|
|
81
|
+
serverError: number;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Fixed-bucket latency histogram in milliseconds. counts[i] is the number of requests with latency <= boundaries[i]; the last bucket holds everything above the last boundary. Fixed buckets add up across instances.
|
|
85
|
+
*/
|
|
86
|
+
interface LatencyHistogram {
|
|
87
|
+
/**
|
|
88
|
+
* @minItems 35
|
|
89
|
+
* @maxItems 35
|
|
90
|
+
*/
|
|
91
|
+
counts: [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number];
|
|
92
|
+
/**
|
|
93
|
+
* Sum of latencies in ms.
|
|
94
|
+
*/
|
|
95
|
+
sum: number;
|
|
96
|
+
/**
|
|
97
|
+
* Maximum latency in ms.
|
|
98
|
+
*/
|
|
99
|
+
max: number;
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/generated/boundaries.d.ts
|
|
103
|
+
/** Upper bounds (ms) of the fixed latency buckets; the last bucket is open-ended. */
|
|
104
|
+
declare const LATENCY_BOUNDARIES_V0: readonly number[];
|
|
105
|
+
/** Number of buckets: boundaries + 1 open-ended bucket. */
|
|
106
|
+
declare const LATENCY_BUCKETS_V0 = 35;
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/index.d.ts
|
|
109
|
+
/** Version of the ingestion protocol spoken by agents and the cloud. */
|
|
110
|
+
declare const PROTOCOL_VERSION = "0.1.0";
|
|
111
|
+
/** Path, relative to the ingest URL, that receives AggregatesBatch payloads. */
|
|
112
|
+
declare const AGGREGATES_PATH = "/v0/aggregates";
|
|
113
|
+
/** The JSON Schema (draft 2020-12) for AggregatesBatch, for validators on either side. */
|
|
114
|
+
declare const AGGREGATES_SCHEMA_V0: {
|
|
115
|
+
$schema: string;
|
|
116
|
+
$id: string;
|
|
117
|
+
title: string;
|
|
118
|
+
description: string;
|
|
119
|
+
type: string;
|
|
120
|
+
additionalProperties: boolean;
|
|
121
|
+
required: string[];
|
|
122
|
+
properties: {
|
|
123
|
+
protocol: {
|
|
124
|
+
type: string;
|
|
125
|
+
const: string;
|
|
126
|
+
description: string;
|
|
127
|
+
};
|
|
128
|
+
agent: {
|
|
129
|
+
$ref: string;
|
|
130
|
+
};
|
|
131
|
+
instance: {
|
|
132
|
+
$ref: string;
|
|
133
|
+
};
|
|
134
|
+
deploy: {
|
|
135
|
+
$ref: string;
|
|
136
|
+
};
|
|
137
|
+
intervals: {
|
|
138
|
+
type: string;
|
|
139
|
+
minItems: number;
|
|
140
|
+
maxItems: number;
|
|
141
|
+
items: {
|
|
142
|
+
$ref: string;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
$defs: {
|
|
147
|
+
AgentInfo: {
|
|
148
|
+
title: string;
|
|
149
|
+
type: string;
|
|
150
|
+
additionalProperties: boolean;
|
|
151
|
+
required: string[];
|
|
152
|
+
properties: {
|
|
153
|
+
name: {
|
|
154
|
+
type: string;
|
|
155
|
+
minLength: number;
|
|
156
|
+
maxLength: number;
|
|
157
|
+
};
|
|
158
|
+
version: {
|
|
159
|
+
type: string;
|
|
160
|
+
minLength: number;
|
|
161
|
+
maxLength: number;
|
|
162
|
+
};
|
|
163
|
+
runtime: {
|
|
164
|
+
enum: string[];
|
|
165
|
+
};
|
|
166
|
+
runtimeVersion: {
|
|
167
|
+
type: string;
|
|
168
|
+
minLength: number;
|
|
169
|
+
maxLength: number;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
InstanceInfo: {
|
|
174
|
+
title: string;
|
|
175
|
+
type: string;
|
|
176
|
+
additionalProperties: boolean;
|
|
177
|
+
required: string[];
|
|
178
|
+
properties: {
|
|
179
|
+
id: {
|
|
180
|
+
type: string;
|
|
181
|
+
minLength: number;
|
|
182
|
+
maxLength: number;
|
|
183
|
+
description: string;
|
|
184
|
+
};
|
|
185
|
+
hostname: {
|
|
186
|
+
type: string;
|
|
187
|
+
minLength: number;
|
|
188
|
+
maxLength: number;
|
|
189
|
+
};
|
|
190
|
+
pid: {
|
|
191
|
+
type: string;
|
|
192
|
+
minimum: number;
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
DeployInfo: {
|
|
197
|
+
title: string;
|
|
198
|
+
type: string;
|
|
199
|
+
additionalProperties: boolean;
|
|
200
|
+
required: string[];
|
|
201
|
+
properties: {
|
|
202
|
+
version: {
|
|
203
|
+
type: string;
|
|
204
|
+
minLength: number;
|
|
205
|
+
maxLength: number;
|
|
206
|
+
description: string;
|
|
207
|
+
};
|
|
208
|
+
environment: {
|
|
209
|
+
type: string;
|
|
210
|
+
minLength: number;
|
|
211
|
+
maxLength: number;
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
Interval: {
|
|
216
|
+
title: string;
|
|
217
|
+
type: string;
|
|
218
|
+
additionalProperties: boolean;
|
|
219
|
+
required: string[];
|
|
220
|
+
properties: {
|
|
221
|
+
start: {
|
|
222
|
+
type: string;
|
|
223
|
+
minimum: number;
|
|
224
|
+
description: string;
|
|
225
|
+
};
|
|
226
|
+
durationMs: {
|
|
227
|
+
type: string;
|
|
228
|
+
minimum: number;
|
|
229
|
+
maximum: number;
|
|
230
|
+
};
|
|
231
|
+
endpoints: {
|
|
232
|
+
type: string;
|
|
233
|
+
maxItems: number;
|
|
234
|
+
items: {
|
|
235
|
+
$ref: string;
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
Endpoint: {
|
|
241
|
+
title: string;
|
|
242
|
+
type: string;
|
|
243
|
+
additionalProperties: boolean;
|
|
244
|
+
required: string[];
|
|
245
|
+
properties: {
|
|
246
|
+
method: {
|
|
247
|
+
enum: string[];
|
|
248
|
+
};
|
|
249
|
+
route: {
|
|
250
|
+
type: string;
|
|
251
|
+
minLength: number;
|
|
252
|
+
maxLength: number;
|
|
253
|
+
description: string;
|
|
254
|
+
};
|
|
255
|
+
count: {
|
|
256
|
+
type: string;
|
|
257
|
+
minimum: number;
|
|
258
|
+
};
|
|
259
|
+
errors: {
|
|
260
|
+
type: string;
|
|
261
|
+
minimum: number;
|
|
262
|
+
description: string;
|
|
263
|
+
};
|
|
264
|
+
status: {
|
|
265
|
+
$ref: string;
|
|
266
|
+
};
|
|
267
|
+
latency: {
|
|
268
|
+
$ref: string;
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
};
|
|
272
|
+
StatusClasses: {
|
|
273
|
+
title: string;
|
|
274
|
+
type: string;
|
|
275
|
+
additionalProperties: boolean;
|
|
276
|
+
required: string[];
|
|
277
|
+
properties: {
|
|
278
|
+
success: {
|
|
279
|
+
type: string;
|
|
280
|
+
minimum: number;
|
|
281
|
+
description: string;
|
|
282
|
+
};
|
|
283
|
+
redirect: {
|
|
284
|
+
type: string;
|
|
285
|
+
minimum: number;
|
|
286
|
+
description: string;
|
|
287
|
+
};
|
|
288
|
+
clientError: {
|
|
289
|
+
type: string;
|
|
290
|
+
minimum: number;
|
|
291
|
+
description: string;
|
|
292
|
+
};
|
|
293
|
+
serverError: {
|
|
294
|
+
type: string;
|
|
295
|
+
minimum: number;
|
|
296
|
+
description: string;
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
};
|
|
300
|
+
LatencyHistogram: {
|
|
301
|
+
title: string;
|
|
302
|
+
description: string;
|
|
303
|
+
type: string;
|
|
304
|
+
additionalProperties: boolean;
|
|
305
|
+
required: string[];
|
|
306
|
+
"x-latency-boundaries-ms": number[];
|
|
307
|
+
properties: {
|
|
308
|
+
counts: {
|
|
309
|
+
type: string;
|
|
310
|
+
minItems: number;
|
|
311
|
+
maxItems: number;
|
|
312
|
+
items: {
|
|
313
|
+
type: string;
|
|
314
|
+
minimum: number;
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
sum: {
|
|
318
|
+
type: string;
|
|
319
|
+
minimum: number;
|
|
320
|
+
description: string;
|
|
321
|
+
};
|
|
322
|
+
max: {
|
|
323
|
+
type: string;
|
|
324
|
+
minimum: number;
|
|
325
|
+
description: string;
|
|
326
|
+
};
|
|
327
|
+
};
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
/** Index of the bucket a latency (ms) falls into: first boundary >= latency, else the open-ended last bucket. */
|
|
332
|
+
declare function latencyBucket(ms: number): number;
|
|
333
|
+
//#endregion
|
|
334
|
+
export { AGGREGATES_PATH, AGGREGATES_SCHEMA_V0, type AgentInfo, type AggregatesBatch, type DeployInfo, type Endpoint, type InstanceInfo, type Interval, LATENCY_BOUNDARIES_V0, LATENCY_BUCKETS_V0, type LatencyHistogram, PROTOCOL_VERSION, type StatusClasses, latencyBucket };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
//#region schema/v0/aggregates.schema.json
|
|
2
|
+
var aggregates_schema_default = {
|
|
3
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
$id: "https://downtrace.io/schema/v0/aggregates.schema.json",
|
|
5
|
+
title: "AggregatesBatch",
|
|
6
|
+
description: "A batch of per-interval, per-route aggregates sent by an agent to the cloud (POST /v0/aggregates).",
|
|
7
|
+
type: "object",
|
|
8
|
+
additionalProperties: false,
|
|
9
|
+
required: [
|
|
10
|
+
"protocol",
|
|
11
|
+
"agent",
|
|
12
|
+
"instance",
|
|
13
|
+
"deploy",
|
|
14
|
+
"intervals"
|
|
15
|
+
],
|
|
16
|
+
properties: {
|
|
17
|
+
"protocol": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"const": "0.1.0",
|
|
20
|
+
"description": "Protocol version this batch conforms to."
|
|
21
|
+
},
|
|
22
|
+
"agent": { "$ref": "#/$defs/AgentInfo" },
|
|
23
|
+
"instance": { "$ref": "#/$defs/InstanceInfo" },
|
|
24
|
+
"deploy": { "$ref": "#/$defs/DeployInfo" },
|
|
25
|
+
"intervals": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"minItems": 1,
|
|
28
|
+
"maxItems": 6,
|
|
29
|
+
"items": { "$ref": "#/$defs/Interval" }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
$defs: {
|
|
33
|
+
"AgentInfo": {
|
|
34
|
+
"title": "AgentInfo",
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"required": [
|
|
38
|
+
"name",
|
|
39
|
+
"version",
|
|
40
|
+
"runtime",
|
|
41
|
+
"runtimeVersion"
|
|
42
|
+
],
|
|
43
|
+
"properties": {
|
|
44
|
+
"name": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"minLength": 1,
|
|
47
|
+
"maxLength": 128
|
|
48
|
+
},
|
|
49
|
+
"version": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"minLength": 1,
|
|
52
|
+
"maxLength": 64
|
|
53
|
+
},
|
|
54
|
+
"runtime": { "enum": ["node", "go"] },
|
|
55
|
+
"runtimeVersion": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"minLength": 1,
|
|
58
|
+
"maxLength": 64
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"InstanceInfo": {
|
|
63
|
+
"title": "InstanceInfo",
|
|
64
|
+
"type": "object",
|
|
65
|
+
"additionalProperties": false,
|
|
66
|
+
"required": [
|
|
67
|
+
"id",
|
|
68
|
+
"hostname",
|
|
69
|
+
"pid"
|
|
70
|
+
],
|
|
71
|
+
"properties": {
|
|
72
|
+
"id": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"minLength": 1,
|
|
75
|
+
"maxLength": 64,
|
|
76
|
+
"description": "Random identifier generated once per process."
|
|
77
|
+
},
|
|
78
|
+
"hostname": {
|
|
79
|
+
"type": "string",
|
|
80
|
+
"minLength": 1,
|
|
81
|
+
"maxLength": 253
|
|
82
|
+
},
|
|
83
|
+
"pid": {
|
|
84
|
+
"type": "integer",
|
|
85
|
+
"minimum": 0
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"DeployInfo": {
|
|
90
|
+
"title": "DeployInfo",
|
|
91
|
+
"type": "object",
|
|
92
|
+
"additionalProperties": false,
|
|
93
|
+
"required": ["version", "environment"],
|
|
94
|
+
"properties": {
|
|
95
|
+
"version": {
|
|
96
|
+
"type": "string",
|
|
97
|
+
"minLength": 1,
|
|
98
|
+
"maxLength": 128,
|
|
99
|
+
"description": "Deployed version or commit; \"unknown\" when undetectable."
|
|
100
|
+
},
|
|
101
|
+
"environment": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"minLength": 1,
|
|
104
|
+
"maxLength": 64
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"Interval": {
|
|
109
|
+
"title": "Interval",
|
|
110
|
+
"type": "object",
|
|
111
|
+
"additionalProperties": false,
|
|
112
|
+
"required": [
|
|
113
|
+
"start",
|
|
114
|
+
"durationMs",
|
|
115
|
+
"endpoints"
|
|
116
|
+
],
|
|
117
|
+
"properties": {
|
|
118
|
+
"start": {
|
|
119
|
+
"type": "integer",
|
|
120
|
+
"minimum": 0,
|
|
121
|
+
"description": "Interval start, Unix epoch milliseconds."
|
|
122
|
+
},
|
|
123
|
+
"durationMs": {
|
|
124
|
+
"type": "integer",
|
|
125
|
+
"minimum": 1,
|
|
126
|
+
"maximum": 36e5
|
|
127
|
+
},
|
|
128
|
+
"endpoints": {
|
|
129
|
+
"type": "array",
|
|
130
|
+
"maxItems": 4096,
|
|
131
|
+
"items": { "$ref": "#/$defs/Endpoint" }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"Endpoint": {
|
|
136
|
+
"title": "Endpoint",
|
|
137
|
+
"type": "object",
|
|
138
|
+
"additionalProperties": false,
|
|
139
|
+
"required": [
|
|
140
|
+
"method",
|
|
141
|
+
"route",
|
|
142
|
+
"count",
|
|
143
|
+
"errors",
|
|
144
|
+
"status",
|
|
145
|
+
"latency"
|
|
146
|
+
],
|
|
147
|
+
"properties": {
|
|
148
|
+
"method": { "enum": [
|
|
149
|
+
"GET",
|
|
150
|
+
"POST",
|
|
151
|
+
"PUT",
|
|
152
|
+
"PATCH",
|
|
153
|
+
"DELETE",
|
|
154
|
+
"HEAD",
|
|
155
|
+
"OPTIONS",
|
|
156
|
+
"OTHER"
|
|
157
|
+
] },
|
|
158
|
+
"route": {
|
|
159
|
+
"type": "string",
|
|
160
|
+
"minLength": 1,
|
|
161
|
+
"maxLength": 256,
|
|
162
|
+
"description": "Normalised route template, e.g. /products/:id, or (other)."
|
|
163
|
+
},
|
|
164
|
+
"count": {
|
|
165
|
+
"type": "integer",
|
|
166
|
+
"minimum": 0
|
|
167
|
+
},
|
|
168
|
+
"errors": {
|
|
169
|
+
"type": "integer",
|
|
170
|
+
"minimum": 0,
|
|
171
|
+
"description": "Responses with a 5xx status."
|
|
172
|
+
},
|
|
173
|
+
"status": { "$ref": "#/$defs/StatusClasses" },
|
|
174
|
+
"latency": { "$ref": "#/$defs/LatencyHistogram" }
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"StatusClasses": {
|
|
178
|
+
"title": "StatusClasses",
|
|
179
|
+
"type": "object",
|
|
180
|
+
"additionalProperties": false,
|
|
181
|
+
"required": [
|
|
182
|
+
"success",
|
|
183
|
+
"redirect",
|
|
184
|
+
"clientError",
|
|
185
|
+
"serverError"
|
|
186
|
+
],
|
|
187
|
+
"properties": {
|
|
188
|
+
"success": {
|
|
189
|
+
"type": "integer",
|
|
190
|
+
"minimum": 0,
|
|
191
|
+
"description": "2xx"
|
|
192
|
+
},
|
|
193
|
+
"redirect": {
|
|
194
|
+
"type": "integer",
|
|
195
|
+
"minimum": 0,
|
|
196
|
+
"description": "3xx"
|
|
197
|
+
},
|
|
198
|
+
"clientError": {
|
|
199
|
+
"type": "integer",
|
|
200
|
+
"minimum": 0,
|
|
201
|
+
"description": "4xx"
|
|
202
|
+
},
|
|
203
|
+
"serverError": {
|
|
204
|
+
"type": "integer",
|
|
205
|
+
"minimum": 0,
|
|
206
|
+
"description": "5xx"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
"LatencyHistogram": {
|
|
211
|
+
"title": "LatencyHistogram",
|
|
212
|
+
"description": "Fixed-bucket latency histogram in milliseconds. counts[i] is the number of requests with latency <= boundaries[i]; the last bucket holds everything above the last boundary. Fixed buckets add up across instances.",
|
|
213
|
+
"type": "object",
|
|
214
|
+
"additionalProperties": false,
|
|
215
|
+
"required": [
|
|
216
|
+
"counts",
|
|
217
|
+
"sum",
|
|
218
|
+
"max"
|
|
219
|
+
],
|
|
220
|
+
"x-latency-boundaries-ms": [
|
|
221
|
+
.5,
|
|
222
|
+
1,
|
|
223
|
+
1.5,
|
|
224
|
+
2,
|
|
225
|
+
3,
|
|
226
|
+
4,
|
|
227
|
+
5,
|
|
228
|
+
7.5,
|
|
229
|
+
10,
|
|
230
|
+
15,
|
|
231
|
+
20,
|
|
232
|
+
30,
|
|
233
|
+
40,
|
|
234
|
+
50,
|
|
235
|
+
75,
|
|
236
|
+
100,
|
|
237
|
+
150,
|
|
238
|
+
200,
|
|
239
|
+
300,
|
|
240
|
+
400,
|
|
241
|
+
500,
|
|
242
|
+
750,
|
|
243
|
+
1e3,
|
|
244
|
+
1500,
|
|
245
|
+
2e3,
|
|
246
|
+
3e3,
|
|
247
|
+
4e3,
|
|
248
|
+
5e3,
|
|
249
|
+
7500,
|
|
250
|
+
1e4,
|
|
251
|
+
15e3,
|
|
252
|
+
2e4,
|
|
253
|
+
3e4,
|
|
254
|
+
6e4
|
|
255
|
+
],
|
|
256
|
+
"properties": {
|
|
257
|
+
"counts": {
|
|
258
|
+
"type": "array",
|
|
259
|
+
"minItems": 35,
|
|
260
|
+
"maxItems": 35,
|
|
261
|
+
"items": {
|
|
262
|
+
"type": "integer",
|
|
263
|
+
"minimum": 0
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
"sum": {
|
|
267
|
+
"type": "number",
|
|
268
|
+
"minimum": 0,
|
|
269
|
+
"description": "Sum of latencies in ms."
|
|
270
|
+
},
|
|
271
|
+
"max": {
|
|
272
|
+
"type": "number",
|
|
273
|
+
"minimum": 0,
|
|
274
|
+
"description": "Maximum latency in ms."
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/generated/boundaries.ts
|
|
282
|
+
/** Upper bounds (ms) of the fixed latency buckets; the last bucket is open-ended. */
|
|
283
|
+
const LATENCY_BOUNDARIES_V0 = [
|
|
284
|
+
.5,
|
|
285
|
+
1,
|
|
286
|
+
1.5,
|
|
287
|
+
2,
|
|
288
|
+
3,
|
|
289
|
+
4,
|
|
290
|
+
5,
|
|
291
|
+
7.5,
|
|
292
|
+
10,
|
|
293
|
+
15,
|
|
294
|
+
20,
|
|
295
|
+
30,
|
|
296
|
+
40,
|
|
297
|
+
50,
|
|
298
|
+
75,
|
|
299
|
+
100,
|
|
300
|
+
150,
|
|
301
|
+
200,
|
|
302
|
+
300,
|
|
303
|
+
400,
|
|
304
|
+
500,
|
|
305
|
+
750,
|
|
306
|
+
1e3,
|
|
307
|
+
1500,
|
|
308
|
+
2e3,
|
|
309
|
+
3e3,
|
|
310
|
+
4e3,
|
|
311
|
+
5e3,
|
|
312
|
+
7500,
|
|
313
|
+
1e4,
|
|
314
|
+
15e3,
|
|
315
|
+
2e4,
|
|
316
|
+
3e4,
|
|
317
|
+
6e4
|
|
318
|
+
];
|
|
319
|
+
/** Number of buckets: boundaries + 1 open-ended bucket. */
|
|
320
|
+
const LATENCY_BUCKETS_V0 = 35;
|
|
321
|
+
//#endregion
|
|
322
|
+
//#region src/index.ts
|
|
323
|
+
/** Version of the ingestion protocol spoken by agents and the cloud. */
|
|
324
|
+
const PROTOCOL_VERSION = "0.1.0";
|
|
325
|
+
/** Path, relative to the ingest URL, that receives AggregatesBatch payloads. */
|
|
326
|
+
const AGGREGATES_PATH = "/v0/aggregates";
|
|
327
|
+
/** The JSON Schema (draft 2020-12) for AggregatesBatch, for validators on either side. */
|
|
328
|
+
const AGGREGATES_SCHEMA_V0 = aggregates_schema_default;
|
|
329
|
+
/** Index of the bucket a latency (ms) falls into: first boundary >= latency, else the open-ended last bucket. */
|
|
330
|
+
function latencyBucket(ms) {
|
|
331
|
+
const n = LATENCY_BOUNDARIES_V0.length;
|
|
332
|
+
for (let i = 0; i < n; i++) {
|
|
333
|
+
const bound = LATENCY_BOUNDARIES_V0[i];
|
|
334
|
+
if (bound !== void 0 && ms <= bound) return i;
|
|
335
|
+
}
|
|
336
|
+
return n;
|
|
337
|
+
}
|
|
338
|
+
//#endregion
|
|
339
|
+
export { AGGREGATES_PATH, AGGREGATES_SCHEMA_V0, LATENCY_BOUNDARIES_V0, LATENCY_BUCKETS_V0, PROTOCOL_VERSION, latencyBucket };
|