@downtrace/protocol 0.2.1 → 0.3.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 CHANGED
@@ -4,7 +4,7 @@ The ingestion contract between Downtrace agents and the Downtrace cloud, as a JS
4
4
 
5
5
  - `schema/v0/aggregates.schema.json` — the contract. Everything else derives from it.
6
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()`, `QUERIES_PER_REQUEST_BOUNDARIES_V0`, `QUERIES_PER_REQUEST_BUCKETS_V0`, `queriesPerRequestBucket()`, and the types `AggregatesBatch`, `Interval`, `Endpoint`, `LatencyHistogram`, `PostgresStats`, …
7
+ - Exports: `PROTOCOL_VERSION`, `AGGREGATES_PATH`, `AGGREGATES_SCHEMA_V0`, `LATENCY_BOUNDARIES_V0`, `LATENCY_BUCKETS_V0`, `latencyBucket()`, `CALLS_PER_REQUEST_BOUNDARIES_V0`, `CALLS_PER_REQUEST_BUCKETS_V0`, `callsPerRequestBucket()`, and the types `AggregatesBatch`, `Interval`, `Endpoint`, `LatencyHistogram`, `Dependency`, `PostgresStats`, …
8
8
 
9
9
  ## v0 in one sentence
10
10
 
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ interface AggregatesBatch {
6
6
  /**
7
7
  * Protocol version this batch conforms to. Every published minor of v0 stays acceptable.
8
8
  */
9
- protocol: "0.1.0" | "0.2.0";
9
+ protocol: "0.1.0" | "0.2.0" | "0.3.0" | "0.4.0";
10
10
  agent: AgentInfo;
11
11
  instance: InstanceInfo;
12
12
  deploy: DeployInfo;
@@ -47,6 +47,7 @@ interface Interval {
47
47
  * @maxItems 4096
48
48
  */
49
49
  endpoints: Endpoint[];
50
+ runtime?: RuntimeHealth;
50
51
  }
51
52
  interface Endpoint {
52
53
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | "OTHER";
@@ -62,6 +63,12 @@ interface Endpoint {
62
63
  status: StatusClasses;
63
64
  latency: LatencyHistogram;
64
65
  postgres?: PostgresStats;
66
+ /**
67
+ * One entry per dependency this route touched. Replaces `postgres` (ADR 0011).
68
+ *
69
+ * @maxItems 64
70
+ */
71
+ dependencies?: Dependency[];
65
72
  }
66
73
  interface StatusClasses {
67
74
  /**
@@ -100,7 +107,7 @@ interface LatencyHistogram {
100
107
  max: number;
101
108
  }
102
109
  /**
103
- * Postgres work done per request on this route during the interval. Optional: agents that do not observe queries omit it.
110
+ * DEPRECATED since 0.4.0, use `dependencies` with kind `postgres` (ADR 0011). Still accepted, and translated at ingest, so agents on 0.2.x and 0.3.x keep working. Will be removed in v1. Its buckets are the same as Dependency's, declared there.
104
111
  */
105
112
  interface PostgresStats {
106
113
  /**
@@ -119,23 +126,97 @@ interface PostgresStats {
119
126
  */
120
127
  max: number;
121
128
  }
129
+ /**
130
+ * What one request did against one dependency, aggregated over the interval for this route. The same shape for every kind, so the cloud stores and compares them uniformly (ADR 0011).
131
+ */
132
+ interface Dependency {
133
+ /**
134
+ * What kind of dependency this is.
135
+ */
136
+ kind: "postgres" | "mysql" | "redis" | "http";
137
+ /**
138
+ * Host for outgoing HTTP (`api.stripe.com`); empty when the dependency is a single one, like the application's own database.
139
+ */
140
+ target: string;
141
+ /**
142
+ * Requests per bucket of calls-per-request; bounds in x-calls-per-request-boundaries, last bucket open-ended.
143
+ *
144
+ * @minItems 8
145
+ * @maxItems 8
146
+ */
147
+ callsPerRequest: [number, number, number, number, number, number, number, number];
148
+ /**
149
+ * Sum of call durations (ms) across every request on this route.
150
+ */
151
+ totalMs: number;
152
+ /**
153
+ * Slowest single call (ms).
154
+ */
155
+ max: number;
156
+ /**
157
+ * Calls that failed.
158
+ */
159
+ errors: number;
160
+ }
161
+ /**
162
+ * Health of the agent's own process during the interval. Optional: an agent that does not measure it omits it. Per interval, not per route, because it belongs to the process.
163
+ */
164
+ interface RuntimeHealth {
165
+ /**
166
+ * How long the event loop was late, in ms. The signal that says the process itself is the bottleneck.
167
+ */
168
+ eventLoopDelayMs: {
169
+ /**
170
+ * Median delay.
171
+ */
172
+ p50: number;
173
+ /**
174
+ * 99th percentile delay.
175
+ */
176
+ p99: number;
177
+ /**
178
+ * Worst delay.
179
+ */
180
+ max: number;
181
+ };
182
+ /**
183
+ * Total time spent in garbage collection during the interval.
184
+ */
185
+ gcPauseMs: number;
186
+ /**
187
+ * Garbage collections during the interval.
188
+ */
189
+ gcCount: number;
190
+ /**
191
+ * Heap in use at the end of the interval.
192
+ */
193
+ heapUsedMb: number;
194
+ /**
195
+ * Resident set size at the end of the interval.
196
+ */
197
+ rssMb: number;
198
+ /**
199
+ * Peak concurrent in-flight requests during the interval.
200
+ */
201
+ inFlightMax: number;
202
+ }
122
203
  //#endregion
123
204
  //#region src/generated/boundaries.d.ts
124
205
  /** Upper bounds (ms) of the fixed latency buckets; the last bucket is open-ended. */
125
206
  declare const LATENCY_BOUNDARIES_V0: readonly number[];
126
207
  /** Number of buckets: boundaries + 1 open-ended bucket. */
127
208
  declare const LATENCY_BUCKETS_V0 = 35;
128
- /** Upper bounds of the fixed queries-per-request buckets; the last bucket is open-ended. */
129
- declare const QUERIES_PER_REQUEST_BOUNDARIES_V0: readonly number[];
130
- /** Number of queries-per-request buckets: boundaries + 1 open-ended bucket. */
131
- declare const QUERIES_PER_REQUEST_BUCKETS_V0 = 8;
209
+ /** Upper bounds of the fixed calls-per-request buckets; the last bucket is open-ended. */
210
+ declare const CALLS_PER_REQUEST_BOUNDARIES_V0: readonly number[];
211
+ /** Number of calls-per-request buckets: boundaries + 1 open-ended bucket. */
212
+ declare const CALLS_PER_REQUEST_BUCKETS_V0 = 8;
132
213
  //#endregion
133
214
  //#region src/index.d.ts
134
215
  /**
135
216
  * Version of the ingestion protocol this package speaks. Every published minor of v0 stays acceptable to the
136
217
  * cloud, so an agent on an older minor keeps working: fields are only ever added, and always optional (ADR 0008).
137
218
  */
138
- declare const PROTOCOL_VERSION = "0.2.0";
219
+ declare const PROTOCOL_VERSION = "0.4.0";
139
220
  /** Path, relative to the ingest URL, that receives AggregatesBatch payloads. */
140
221
  declare const AGGREGATES_PATH = "/v0/aggregates";
141
222
  /** The JSON Schema (draft 2020-12) for AggregatesBatch, for validators on either side. */
@@ -263,6 +344,9 @@ declare const AGGREGATES_SCHEMA_V0: {
263
344
  $ref: string;
264
345
  };
265
346
  };
347
+ runtime: {
348
+ $ref: string;
349
+ };
266
350
  };
267
351
  };
268
352
  Endpoint: {
@@ -298,6 +382,14 @@ declare const AGGREGATES_SCHEMA_V0: {
298
382
  postgres: {
299
383
  $ref: string;
300
384
  };
385
+ dependencies: {
386
+ type: string;
387
+ description: string;
388
+ maxItems: number;
389
+ items: {
390
+ $ref: string;
391
+ };
392
+ };
301
393
  };
302
394
  };
303
395
  StatusClasses: {
@@ -363,7 +455,6 @@ declare const AGGREGATES_SCHEMA_V0: {
363
455
  type: string;
364
456
  additionalProperties: boolean;
365
457
  required: string[];
366
- "x-queries-per-request-boundaries": number[];
367
458
  properties: {
368
459
  queriesPerRequest: {
369
460
  type: string;
@@ -387,11 +478,112 @@ declare const AGGREGATES_SCHEMA_V0: {
387
478
  };
388
479
  };
389
480
  };
481
+ RuntimeHealth: {
482
+ title: string;
483
+ description: string;
484
+ type: string;
485
+ additionalProperties: boolean;
486
+ required: string[];
487
+ properties: {
488
+ eventLoopDelayMs: {
489
+ type: string;
490
+ additionalProperties: boolean;
491
+ required: string[];
492
+ description: string;
493
+ properties: {
494
+ p50: {
495
+ type: string;
496
+ minimum: number;
497
+ description: string;
498
+ };
499
+ p99: {
500
+ type: string;
501
+ minimum: number;
502
+ description: string;
503
+ };
504
+ max: {
505
+ type: string;
506
+ minimum: number;
507
+ description: string;
508
+ };
509
+ };
510
+ };
511
+ gcPauseMs: {
512
+ type: string;
513
+ minimum: number;
514
+ description: string;
515
+ };
516
+ gcCount: {
517
+ type: string;
518
+ minimum: number;
519
+ description: string;
520
+ };
521
+ heapUsedMb: {
522
+ type: string;
523
+ minimum: number;
524
+ description: string;
525
+ };
526
+ rssMb: {
527
+ type: string;
528
+ minimum: number;
529
+ description: string;
530
+ };
531
+ inFlightMax: {
532
+ type: string;
533
+ minimum: number;
534
+ description: string;
535
+ };
536
+ };
537
+ };
538
+ Dependency: {
539
+ title: string;
540
+ description: string;
541
+ type: string;
542
+ additionalProperties: boolean;
543
+ required: string[];
544
+ "x-calls-per-request-boundaries": number[];
545
+ properties: {
546
+ kind: {
547
+ enum: string[];
548
+ description: string;
549
+ };
550
+ target: {
551
+ type: string;
552
+ maxLength: number;
553
+ description: string;
554
+ };
555
+ callsPerRequest: {
556
+ type: string;
557
+ description: string;
558
+ minItems: number;
559
+ maxItems: number;
560
+ items: {
561
+ type: string;
562
+ minimum: number;
563
+ };
564
+ };
565
+ totalMs: {
566
+ type: string;
567
+ minimum: number;
568
+ description: string;
569
+ };
570
+ max: {
571
+ type: string;
572
+ minimum: number;
573
+ description: string;
574
+ };
575
+ errors: {
576
+ type: string;
577
+ minimum: number;
578
+ description: string;
579
+ };
580
+ };
581
+ };
390
582
  };
391
583
  };
392
584
  /** Index of the bucket a latency (ms) falls into: first boundary >= latency, else the open-ended last bucket. */
393
585
  declare function latencyBucket(ms: number): number;
394
- /** Index of the bucket a query count falls into: first boundary >= count, else the open-ended last bucket. */
395
- declare function queriesPerRequestBucket(queries: number): number;
586
+ /** Index of the bucket a call count falls into: first boundary >= count, else the open-ended last bucket. */
587
+ declare function callsPerRequestBucket(calls: number): number;
396
588
  //#endregion
397
- 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 PostgresStats, QUERIES_PER_REQUEST_BOUNDARIES_V0, QUERIES_PER_REQUEST_BUCKETS_V0, type StatusClasses, latencyBucket, queriesPerRequestBucket };
589
+ export { AGGREGATES_PATH, AGGREGATES_SCHEMA_V0, type AgentInfo, type AggregatesBatch, CALLS_PER_REQUEST_BOUNDARIES_V0, CALLS_PER_REQUEST_BUCKETS_V0, type Dependency, type DeployInfo, type Endpoint, type InstanceInfo, type Interval, LATENCY_BOUNDARIES_V0, LATENCY_BUCKETS_V0, type LatencyHistogram, PROTOCOL_VERSION, type PostgresStats, type RuntimeHealth, type StatusClasses, callsPerRequestBucket, latencyBucket };
package/dist/index.js CHANGED
@@ -16,7 +16,12 @@ var aggregates_schema_default = {
16
16
  properties: {
17
17
  "protocol": {
18
18
  "type": "string",
19
- "enum": ["0.1.0", "0.2.0"],
19
+ "enum": [
20
+ "0.1.0",
21
+ "0.2.0",
22
+ "0.3.0",
23
+ "0.4.0"
24
+ ],
20
25
  "description": "Protocol version this batch conforms to. Every published minor of v0 stays acceptable."
21
26
  },
22
27
  "agent": { "$ref": "#/$defs/AgentInfo" },
@@ -129,7 +134,8 @@ var aggregates_schema_default = {
129
134
  "type": "array",
130
135
  "maxItems": 4096,
131
136
  "items": { "$ref": "#/$defs/Endpoint" }
132
- }
137
+ },
138
+ "runtime": { "$ref": "#/$defs/RuntimeHealth" }
133
139
  }
134
140
  },
135
141
  "Endpoint": {
@@ -172,7 +178,13 @@ var aggregates_schema_default = {
172
178
  },
173
179
  "status": { "$ref": "#/$defs/StatusClasses" },
174
180
  "latency": { "$ref": "#/$defs/LatencyHistogram" },
175
- "postgres": { "$ref": "#/$defs/PostgresStats" }
181
+ "postgres": { "$ref": "#/$defs/PostgresStats" },
182
+ "dependencies": {
183
+ "type": "array",
184
+ "description": "One entry per dependency this route touched. Replaces `postgres` (ADR 0011).",
185
+ "maxItems": 64,
186
+ "items": { "$ref": "#/$defs/Dependency" }
187
+ }
176
188
  }
177
189
  },
178
190
  "StatusClasses": {
@@ -278,7 +290,7 @@ var aggregates_schema_default = {
278
290
  },
279
291
  "PostgresStats": {
280
292
  "title": "PostgresStats",
281
- "description": "Postgres work done per request on this route during the interval. Optional: agents that do not observe queries omit it.",
293
+ "description": "DEPRECATED since 0.4.0, use `dependencies` with kind `postgres` (ADR 0011). Still accepted, and translated at ingest, so agents on 0.2.x and 0.3.x keep working. Will be removed in v1. Its buckets are the same as Dependency's, declared there.",
282
294
  "type": "object",
283
295
  "additionalProperties": false,
284
296
  "required": [
@@ -286,7 +298,111 @@ var aggregates_schema_default = {
286
298
  "totalMs",
287
299
  "max"
288
300
  ],
289
- "x-queries-per-request-boundaries": [
301
+ "properties": {
302
+ "queriesPerRequest": {
303
+ "type": "array",
304
+ "description": "Requests per bucket of queries-per-request; bounds in x-queries-per-request-boundaries, last bucket open-ended.",
305
+ "minItems": 8,
306
+ "maxItems": 8,
307
+ "items": {
308
+ "type": "integer",
309
+ "minimum": 0
310
+ }
311
+ },
312
+ "totalMs": {
313
+ "type": "number",
314
+ "minimum": 0,
315
+ "description": "Sum of query durations (ms) across every request on this route."
316
+ },
317
+ "max": {
318
+ "type": "number",
319
+ "minimum": 0,
320
+ "description": "Slowest single query (ms)."
321
+ }
322
+ }
323
+ },
324
+ "RuntimeHealth": {
325
+ "title": "RuntimeHealth",
326
+ "description": "Health of the agent's own process during the interval. Optional: an agent that does not measure it omits it. Per interval, not per route, because it belongs to the process.",
327
+ "type": "object",
328
+ "additionalProperties": false,
329
+ "required": [
330
+ "eventLoopDelayMs",
331
+ "gcPauseMs",
332
+ "gcCount",
333
+ "heapUsedMb",
334
+ "rssMb",
335
+ "inFlightMax"
336
+ ],
337
+ "properties": {
338
+ "eventLoopDelayMs": {
339
+ "type": "object",
340
+ "additionalProperties": false,
341
+ "required": [
342
+ "p50",
343
+ "p99",
344
+ "max"
345
+ ],
346
+ "description": "How long the event loop was late, in ms. The signal that says the process itself is the bottleneck.",
347
+ "properties": {
348
+ "p50": {
349
+ "type": "number",
350
+ "minimum": 0,
351
+ "description": "Median delay."
352
+ },
353
+ "p99": {
354
+ "type": "number",
355
+ "minimum": 0,
356
+ "description": "99th percentile delay."
357
+ },
358
+ "max": {
359
+ "type": "number",
360
+ "minimum": 0,
361
+ "description": "Worst delay."
362
+ }
363
+ }
364
+ },
365
+ "gcPauseMs": {
366
+ "type": "number",
367
+ "minimum": 0,
368
+ "description": "Total time spent in garbage collection during the interval."
369
+ },
370
+ "gcCount": {
371
+ "type": "integer",
372
+ "minimum": 0,
373
+ "description": "Garbage collections during the interval."
374
+ },
375
+ "heapUsedMb": {
376
+ "type": "number",
377
+ "minimum": 0,
378
+ "description": "Heap in use at the end of the interval."
379
+ },
380
+ "rssMb": {
381
+ "type": "number",
382
+ "minimum": 0,
383
+ "description": "Resident set size at the end of the interval."
384
+ },
385
+ "inFlightMax": {
386
+ "type": "integer",
387
+ "minimum": 0,
388
+ "description": "Peak concurrent in-flight requests during the interval."
389
+ }
390
+ }
391
+ },
392
+ "Dependency": {
393
+ "title": "Dependency",
394
+ "description": "What one request did against one dependency, aggregated over the interval for this route. The same shape for every kind, so the cloud stores and compares them uniformly (ADR 0011).",
395
+ "type": "object",
396
+ "additionalProperties": false,
397
+ "required": [
398
+ "kind",
399
+ "target",
400
+ "callsPerRequest",
401
+ "totalMs",
402
+ "max",
403
+ "errors"
404
+ ],
405
+ "x-calls-per-request-boundaries": [
290
406
  0,
291
407
  1,
292
408
  2,
@@ -296,9 +412,23 @@ var aggregates_schema_default = {
296
412
  50
297
413
  ],
298
414
  "properties": {
299
- "queriesPerRequest": {
415
+ "kind": {
416
+ "enum": [
417
+ "postgres",
418
+ "mysql",
419
+ "redis",
420
+ "http"
421
+ ],
422
+ "description": "What kind of dependency this is."
423
+ },
424
+ "target": {
425
+ "type": "string",
426
+ "maxLength": 256,
427
+ "description": "Host for outgoing HTTP (`api.stripe.com`); empty when the dependency is a single one, like the application's own database."
428
+ },
429
+ "callsPerRequest": {
300
430
  "type": "array",
301
- "description": "Requests per bucket of queries-per-request; bounds in x-queries-per-request-boundaries, last bucket open-ended.",
431
+ "description": "Requests per bucket of calls-per-request; bounds in x-calls-per-request-boundaries, last bucket open-ended.",
302
432
  "minItems": 8,
303
433
  "maxItems": 8,
304
434
  "items": {
@@ -309,12 +439,17 @@ var aggregates_schema_default = {
309
439
  "totalMs": {
310
440
  "type": "number",
311
441
  "minimum": 0,
312
- "description": "Sum of query durations (ms) across every request on this route."
442
+ "description": "Sum of call durations (ms) across every request on this route."
313
443
  },
314
444
  "max": {
315
445
  "type": "number",
316
446
  "minimum": 0,
317
- "description": "Slowest single query (ms)."
447
+ "description": "Slowest single call (ms)."
448
+ },
449
+ "errors": {
450
+ "type": "integer",
451
+ "minimum": 0,
452
+ "description": "Calls that failed."
318
453
  }
319
454
  }
320
455
  }
@@ -361,8 +496,8 @@ const LATENCY_BOUNDARIES_V0 = [
361
496
  ];
362
497
  /** Number of buckets: boundaries + 1 open-ended bucket. */
363
498
  const LATENCY_BUCKETS_V0 = 35;
364
- /** Upper bounds of the fixed queries-per-request buckets; the last bucket is open-ended. */
365
- const QUERIES_PER_REQUEST_BOUNDARIES_V0 = [
499
+ /** Upper bounds of the fixed calls-per-request buckets; the last bucket is open-ended. */
500
+ const CALLS_PER_REQUEST_BOUNDARIES_V0 = [
366
501
  0,
367
502
  1,
368
503
  2,
@@ -371,15 +506,15 @@ const QUERIES_PER_REQUEST_BOUNDARIES_V0 = [
371
506
  20,
372
507
  50
373
508
  ];
374
- /** Number of queries-per-request buckets: boundaries + 1 open-ended bucket. */
375
- const QUERIES_PER_REQUEST_BUCKETS_V0 = 8;
509
+ /** Number of calls-per-request buckets: boundaries + 1 open-ended bucket. */
510
+ const CALLS_PER_REQUEST_BUCKETS_V0 = 8;
376
511
  //#endregion
377
512
  //#region src/index.ts
378
513
  /**
379
514
  * Version of the ingestion protocol this package speaks. Every published minor of v0 stays acceptable to the
380
515
  * cloud, so an agent on an older minor keeps working: fields are only ever added, and always optional (ADR 0008).
381
516
  */
382
- const PROTOCOL_VERSION = "0.2.0";
517
+ const PROTOCOL_VERSION = "0.4.0";
383
518
  /** Path, relative to the ingest URL, that receives AggregatesBatch payloads. */
384
519
  const AGGREGATES_PATH = "/v0/aggregates";
385
520
  /** The JSON Schema (draft 2020-12) for AggregatesBatch, for validators on either side. */
@@ -393,14 +528,14 @@ function latencyBucket(ms) {
393
528
  }
394
529
  return n;
395
530
  }
396
- /** Index of the bucket a query count falls into: first boundary >= count, else the open-ended last bucket. */
397
- function queriesPerRequestBucket(queries) {
398
- const n = QUERIES_PER_REQUEST_BOUNDARIES_V0.length;
531
+ /** Index of the bucket a call count falls into: first boundary >= count, else the open-ended last bucket. */
532
+ function callsPerRequestBucket(calls) {
533
+ const n = CALLS_PER_REQUEST_BOUNDARIES_V0.length;
399
534
  for (let i = 0; i < n; i++) {
400
- const bound = QUERIES_PER_REQUEST_BOUNDARIES_V0[i];
401
- if (bound !== void 0 && queries <= bound) return i;
535
+ const bound = CALLS_PER_REQUEST_BOUNDARIES_V0[i];
536
+ if (bound !== void 0 && calls <= bound) return i;
402
537
  }
403
538
  return n;
404
539
  }
405
540
  //#endregion
406
- export { AGGREGATES_PATH, AGGREGATES_SCHEMA_V0, LATENCY_BOUNDARIES_V0, LATENCY_BUCKETS_V0, PROTOCOL_VERSION, QUERIES_PER_REQUEST_BOUNDARIES_V0, QUERIES_PER_REQUEST_BUCKETS_V0, latencyBucket, queriesPerRequestBucket };
541
+ export { AGGREGATES_PATH, AGGREGATES_SCHEMA_V0, CALLS_PER_REQUEST_BOUNDARIES_V0, CALLS_PER_REQUEST_BUCKETS_V0, LATENCY_BOUNDARIES_V0, LATENCY_BUCKETS_V0, PROTOCOL_VERSION, callsPerRequestBucket, latencyBucket };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@downtrace/protocol",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Downtrace ingestion protocol: JSON Schema, fixtures and generated TypeScript types",
5
5
  "type": "module",
6
6
  "exports": {
@@ -9,7 +9,7 @@
9
9
  "properties": {
10
10
  "protocol": {
11
11
  "type": "string",
12
- "enum": ["0.1.0", "0.2.0"],
12
+ "enum": ["0.1.0", "0.2.0", "0.3.0", "0.4.0"],
13
13
  "description": "Protocol version this batch conforms to. Every published minor of v0 stays acceptable."
14
14
  },
15
15
  "agent": {
@@ -121,6 +121,9 @@
121
121
  "items": {
122
122
  "$ref": "#/$defs/Endpoint"
123
123
  }
124
+ },
125
+ "runtime": {
126
+ "$ref": "#/$defs/RuntimeHealth"
124
127
  }
125
128
  }
126
129
  },
@@ -156,6 +159,14 @@
156
159
  },
157
160
  "postgres": {
158
161
  "$ref": "#/$defs/PostgresStats"
162
+ },
163
+ "dependencies": {
164
+ "type": "array",
165
+ "description": "One entry per dependency this route touched. Replaces `postgres` (ADR 0011).",
166
+ "maxItems": 64,
167
+ "items": {
168
+ "$ref": "#/$defs/Dependency"
169
+ }
159
170
  }
160
171
  }
161
172
  },
@@ -221,11 +232,10 @@
221
232
  },
222
233
  "PostgresStats": {
223
234
  "title": "PostgresStats",
224
- "description": "Postgres work done per request on this route during the interval. Optional: agents that do not observe queries omit it.",
235
+ "description": "DEPRECATED since 0.4.0, use `dependencies` with kind `postgres` (ADR 0011). Still accepted, and translated at ingest, so agents on 0.2.x and 0.3.x keep working. Will be removed in v1. Its buckets are the same as Dependency's, declared there.",
225
236
  "type": "object",
226
237
  "additionalProperties": false,
227
238
  "required": ["queriesPerRequest", "totalMs", "max"],
228
- "x-queries-per-request-boundaries": [0, 1, 2, 5, 10, 20, 50],
229
239
  "properties": {
230
240
  "queriesPerRequest": {
231
241
  "type": "array",
@@ -248,6 +258,107 @@
248
258
  "description": "Slowest single query (ms)."
249
259
  }
250
260
  }
261
+ },
262
+ "RuntimeHealth": {
263
+ "title": "RuntimeHealth",
264
+ "description": "Health of the agent's own process during the interval. Optional: an agent that does not measure it omits it. Per interval, not per route, because it belongs to the process.",
265
+ "type": "object",
266
+ "additionalProperties": false,
267
+ "required": ["eventLoopDelayMs", "gcPauseMs", "gcCount", "heapUsedMb", "rssMb", "inFlightMax"],
268
+ "properties": {
269
+ "eventLoopDelayMs": {
270
+ "type": "object",
271
+ "additionalProperties": false,
272
+ "required": ["p50", "p99", "max"],
273
+ "description": "How long the event loop was late, in ms. The signal that says the process itself is the bottleneck.",
274
+ "properties": {
275
+ "p50": {
276
+ "type": "number",
277
+ "minimum": 0,
278
+ "description": "Median delay."
279
+ },
280
+ "p99": {
281
+ "type": "number",
282
+ "minimum": 0,
283
+ "description": "99th percentile delay."
284
+ },
285
+ "max": {
286
+ "type": "number",
287
+ "minimum": 0,
288
+ "description": "Worst delay."
289
+ }
290
+ }
291
+ },
292
+ "gcPauseMs": {
293
+ "type": "number",
294
+ "minimum": 0,
295
+ "description": "Total time spent in garbage collection during the interval."
296
+ },
297
+ "gcCount": {
298
+ "type": "integer",
299
+ "minimum": 0,
300
+ "description": "Garbage collections during the interval."
301
+ },
302
+ "heapUsedMb": {
303
+ "type": "number",
304
+ "minimum": 0,
305
+ "description": "Heap in use at the end of the interval."
306
+ },
307
+ "rssMb": {
308
+ "type": "number",
309
+ "minimum": 0,
310
+ "description": "Resident set size at the end of the interval."
311
+ },
312
+ "inFlightMax": {
313
+ "type": "integer",
314
+ "minimum": 0,
315
+ "description": "Peak concurrent in-flight requests during the interval."
316
+ }
317
+ }
318
+ },
319
+ "Dependency": {
320
+ "title": "Dependency",
321
+ "description": "What one request did against one dependency, aggregated over the interval for this route. The same shape for every kind, so the cloud stores and compares them uniformly (ADR 0011).",
322
+ "type": "object",
323
+ "additionalProperties": false,
324
+ "required": ["kind", "target", "callsPerRequest", "totalMs", "max", "errors"],
325
+ "x-calls-per-request-boundaries": [0, 1, 2, 5, 10, 20, 50],
326
+ "properties": {
327
+ "kind": {
328
+ "enum": ["postgres", "mysql", "redis", "http"],
329
+ "description": "What kind of dependency this is."
330
+ },
331
+ "target": {
332
+ "type": "string",
333
+ "maxLength": 256,
334
+ "description": "Host for outgoing HTTP (`api.stripe.com`); empty when the dependency is a single one, like the application's own database."
335
+ },
336
+ "callsPerRequest": {
337
+ "type": "array",
338
+ "description": "Requests per bucket of calls-per-request; bounds in x-calls-per-request-boundaries, last bucket open-ended.",
339
+ "minItems": 8,
340
+ "maxItems": 8,
341
+ "items": {
342
+ "type": "integer",
343
+ "minimum": 0
344
+ }
345
+ },
346
+ "totalMs": {
347
+ "type": "number",
348
+ "minimum": 0,
349
+ "description": "Sum of call durations (ms) across every request on this route."
350
+ },
351
+ "max": {
352
+ "type": "number",
353
+ "minimum": 0,
354
+ "description": "Slowest single call (ms)."
355
+ },
356
+ "errors": {
357
+ "type": "integer",
358
+ "minimum": 0,
359
+ "description": "Calls that failed."
360
+ }
361
+ }
251
362
  }
252
363
  }
253
364
  }
@@ -0,0 +1,83 @@
1
+ {
2
+ "protocol": "0.4.0",
3
+ "agent": {
4
+ "name": "@downtrace/agent",
5
+ "version": "0.0.0",
6
+ "runtime": "node",
7
+ "runtimeVersion": "v24.0.0"
8
+ },
9
+ "instance": {
10
+ "id": "7d1e9c6a-4f2b-4c1e-9b0a-2f6d3e8a1c55",
11
+ "hostname": "web-1",
12
+ "pid": 4242
13
+ },
14
+ "deploy": {
15
+ "version": "8f71ac2",
16
+ "environment": "production"
17
+ },
18
+ "intervals": [
19
+ {
20
+ "start": 1756900000000,
21
+ "durationMs": 10000,
22
+ "endpoints": [
23
+ {
24
+ "method": "POST",
25
+ "route": "/checkout",
26
+ "count": 3,
27
+ "errors": 0,
28
+ "status": {
29
+ "success": 3,
30
+ "redirect": 0,
31
+ "clientError": 0,
32
+ "serverError": 0
33
+ },
34
+ "latency": {
35
+ "counts": [
36
+ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
37
+ ],
38
+ "sum": 2.4,
39
+ "max": 0.9
40
+ },
41
+ "dependencies": [
42
+ {
43
+ "kind": "cassandra",
44
+ "target": "",
45
+ "callsPerRequest": [0, 0, 0, 0, 0, 3, 0, 0],
46
+ "totalMs": 41.25,
47
+ "max": 9.5,
48
+ "errors": 0
49
+ },
50
+ {
51
+ "kind": "http",
52
+ "target": "api.stripe.com",
53
+ "callsPerRequest": [0, 0, 3, 0, 0, 0, 0, 0],
54
+ "totalMs": 612.4,
55
+ "max": 240.1,
56
+ "errors": 1
57
+ },
58
+ {
59
+ "kind": "redis",
60
+ "target": "",
61
+ "callsPerRequest": [0, 0, 0, 3, 0, 0, 0, 0],
62
+ "totalMs": 4.2,
63
+ "max": 1.1,
64
+ "errors": 0
65
+ }
66
+ ]
67
+ }
68
+ ],
69
+ "runtime": {
70
+ "eventLoopDelayMs": {
71
+ "p50": 0.9,
72
+ "p99": 14.2,
73
+ "max": 61.5
74
+ },
75
+ "gcPauseMs": 22.4,
76
+ "gcCount": 7,
77
+ "heapUsedMb": 48.6,
78
+ "rssMb": 131.2,
79
+ "inFlightMax": 9
80
+ }
81
+ }
82
+ ]
83
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "protocol": "0.3.0",
3
+ "agent": {
4
+ "name": "@downtrace/agent",
5
+ "version": "0.0.0",
6
+ "runtime": "node",
7
+ "runtimeVersion": "v24.0.0"
8
+ },
9
+ "instance": {
10
+ "id": "7d1e9c6a-4f2b-4c1e-9b0a-2f6d3e8a1c55",
11
+ "hostname": "web-1",
12
+ "pid": 4242
13
+ },
14
+ "deploy": {
15
+ "version": "8f71ac2",
16
+ "environment": "production"
17
+ },
18
+ "intervals": [
19
+ {
20
+ "start": 1756900000000,
21
+ "durationMs": 10000,
22
+ "endpoints": [
23
+ {
24
+ "method": "POST",
25
+ "route": "/checkout",
26
+ "count": 3,
27
+ "errors": 0,
28
+ "status": {
29
+ "success": 3,
30
+ "redirect": 0,
31
+ "clientError": 0,
32
+ "serverError": 0
33
+ },
34
+ "latency": {
35
+ "counts": [
36
+ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
37
+ ],
38
+ "sum": 2.4,
39
+ "max": 0.9
40
+ },
41
+ "postgres": {
42
+ "queriesPerRequest": [0, 0, 0, 0, 0, 3, 0, 0],
43
+ "totalMs": 41.25,
44
+ "max": 9.5
45
+ }
46
+ }
47
+ ],
48
+ "runtime": {
49
+ "eventLoopDelayMs": {
50
+ "p50": 0.9,
51
+ "p99": 14.2,
52
+ "max": 61.5
53
+ },
54
+ "gcPauseMs": 22.4,
55
+ "gcCount": 7,
56
+ "heapUsedMb": 48.6,
57
+ "inFlightMax": 9
58
+ }
59
+ }
60
+ ]
61
+ }
@@ -0,0 +1,83 @@
1
+ {
2
+ "protocol": "0.4.0",
3
+ "agent": {
4
+ "name": "@downtrace/agent",
5
+ "version": "0.0.0",
6
+ "runtime": "node",
7
+ "runtimeVersion": "v24.0.0"
8
+ },
9
+ "instance": {
10
+ "id": "7d1e9c6a-4f2b-4c1e-9b0a-2f6d3e8a1c55",
11
+ "hostname": "web-1",
12
+ "pid": 4242
13
+ },
14
+ "deploy": {
15
+ "version": "8f71ac2",
16
+ "environment": "production"
17
+ },
18
+ "intervals": [
19
+ {
20
+ "start": 1756900000000,
21
+ "durationMs": 10000,
22
+ "endpoints": [
23
+ {
24
+ "method": "POST",
25
+ "route": "/checkout",
26
+ "count": 3,
27
+ "errors": 0,
28
+ "status": {
29
+ "success": 3,
30
+ "redirect": 0,
31
+ "clientError": 0,
32
+ "serverError": 0
33
+ },
34
+ "latency": {
35
+ "counts": [
36
+ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
37
+ ],
38
+ "sum": 2.4,
39
+ "max": 0.9
40
+ },
41
+ "dependencies": [
42
+ {
43
+ "kind": "postgres",
44
+ "target": "",
45
+ "callsPerRequest": [0, 0, 0, 0, 0, 3, 0, 0],
46
+ "totalMs": 41.25,
47
+ "max": 9.5,
48
+ "errors": 0
49
+ },
50
+ {
51
+ "kind": "http",
52
+ "target": "api.stripe.com",
53
+ "callsPerRequest": [0, 0, 3, 0, 0, 0, 0, 0],
54
+ "totalMs": 612.4,
55
+ "max": 240.1,
56
+ "errors": 1
57
+ },
58
+ {
59
+ "kind": "redis",
60
+ "target": "",
61
+ "callsPerRequest": [0, 0, 0, 3, 0, 0, 0, 0],
62
+ "totalMs": 4.2,
63
+ "max": 1.1,
64
+ "errors": 0
65
+ }
66
+ ]
67
+ }
68
+ ],
69
+ "runtime": {
70
+ "eventLoopDelayMs": {
71
+ "p50": 0.9,
72
+ "p99": 14.2,
73
+ "max": 61.5
74
+ },
75
+ "gcPauseMs": 22.4,
76
+ "gcCount": 7,
77
+ "heapUsedMb": 48.6,
78
+ "rssMb": 131.2,
79
+ "inFlightMax": 9
80
+ }
81
+ }
82
+ ]
83
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "protocol": "0.3.0",
3
+ "agent": {
4
+ "name": "@downtrace/agent",
5
+ "version": "0.0.0",
6
+ "runtime": "node",
7
+ "runtimeVersion": "v24.0.0"
8
+ },
9
+ "instance": {
10
+ "id": "7d1e9c6a-4f2b-4c1e-9b0a-2f6d3e8a1c55",
11
+ "hostname": "web-1",
12
+ "pid": 4242
13
+ },
14
+ "deploy": {
15
+ "version": "8f71ac2",
16
+ "environment": "production"
17
+ },
18
+ "intervals": [
19
+ {
20
+ "start": 1756900000000,
21
+ "durationMs": 10000,
22
+ "endpoints": [
23
+ {
24
+ "method": "POST",
25
+ "route": "/checkout",
26
+ "count": 3,
27
+ "errors": 0,
28
+ "status": {
29
+ "success": 3,
30
+ "redirect": 0,
31
+ "clientError": 0,
32
+ "serverError": 0
33
+ },
34
+ "latency": {
35
+ "counts": [
36
+ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
37
+ ],
38
+ "sum": 2.4,
39
+ "max": 0.9
40
+ },
41
+ "postgres": {
42
+ "queriesPerRequest": [0, 0, 0, 0, 0, 3, 0, 0],
43
+ "totalMs": 41.25,
44
+ "max": 9.5
45
+ }
46
+ }
47
+ ],
48
+ "runtime": {
49
+ "eventLoopDelayMs": {
50
+ "p50": 0.9,
51
+ "p99": 14.2,
52
+ "max": 61.5
53
+ },
54
+ "gcPauseMs": 22.4,
55
+ "gcCount": 7,
56
+ "heapUsedMb": 48.6,
57
+ "rssMb": 131.2,
58
+ "inFlightMax": 9
59
+ }
60
+ }
61
+ ]
62
+ }