@downtrace/agent 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
@@ -33,12 +33,39 @@ Without `DOWNTRACE_TOKEN` and `DOWNTRACE_URL` (or with a `DOWNTRACE_URL` that is
33
33
 
34
34
  Only structural metadata: method, **route template** (`/products/:id`, never the actual URL), status, counts and a fixed-bucket latency histogram per route and interval, plus the process identity (random id, hostname, pid) and the deploy (version, environment). No bodies, no headers, no query strings. The exact contract is the JSON Schema in [`@downtrace/protocol`](https://www.npmjs.com/package/@downtrace/protocol).
35
35
 
36
+ ### The health of your process
37
+
38
+ Every interval the agent also reports how late Node's event loop ran (median, p99 and worst), how much time went to
39
+ garbage collection, heap and resident memory, and the peak number of requests in flight. In Node many slowdowns are
40
+ neither the database nor the network but the process itself, and a diagnosis that does not measure it will blame
41
+ whatever it does measure. It all comes from Node's own instruments, which run whether anyone looks at them or not.
42
+
36
43
  ### Database work per request
37
44
 
38
- When your application uses `pg`, the agent also counts the queries each request makes, how long they took in total
39
- and the slowest one, and reports that distribution per route. It is what turns "this endpoint got slower" into "this
40
- endpoint went from 12 queries per request to 65". **It never reads the query text or its values**, only counts and
41
- durations.
45
+ When your application uses `pg`, the agent also counts the calls each request makes to it, how long they took in
46
+ total, the slowest one and how many failed, and reports that distribution per route. It is what turns "this endpoint
47
+ got slower" into "this endpoint went from 12 queries per request to 65". **It never reads the query text or its
48
+ values**, only counts and durations.
49
+
50
+ ### Calls to other services
51
+
52
+ Outgoing HTTP is reported the same way, grouped by the host your application asked for: how many calls per request,
53
+ how long they took, the slowest one, and how many failed. A 5xx from a dependency counts as a failure of that
54
+ dependency, because for "is this service degraded?" a 500 and a timeout are the same answer.
55
+
56
+ `fetch` and the `node:http` client both publish on Node's `diagnostics_channel`, and the agent listens. There is one
57
+ exception: when a `fetch` cannot connect at all, undici publishes nothing, and that is exactly the case where a
58
+ dependency is down. For that, and only that, the agent wraps `globalThis.fetch`: if a call rejects and nothing was
59
+ recorded for it, it counts as a failed call. On every other path the wrapper does nothing.
60
+
61
+ ### Redis
62
+
63
+ The commands each request issues are reported the same way, per server: how many per request, how long they took and
64
+ how many failed. ioredis publishes on a tracing channel, so nothing is patched.
65
+
66
+ Every dependency carries a **target** saying which instance of its kind it is, taken from the driver: the host for
67
+ outgoing HTTP, host and port for Postgres and Redis. A read replica and a primary are two dependencies, not one.
68
+ MySQL will appear the same way when it is added.
42
69
 
43
70
  The agent loads before your application (`node --import`), so it wraps the driver before you import it and you write
44
71
  no code. The wrapper passes arguments, results and errors through untouched, and a failure inside it runs your query
package/dist/index.d.ts CHANGED
@@ -1,4 +1,16 @@
1
- import { AgentInfo, DeployInfo, Endpoint, InstanceInfo, Interval } from "@downtrace/protocol";
1
+ import { AgentInfo, Dependency, DeployInfo, Endpoint, InstanceInfo, Interval } from "@downtrace/protocol";
2
+ //#region src/context.d.ts
3
+ type DependencyKind = Dependency["kind"];
4
+ /** What one request did against one dependency. Counters only: never the query text, never the values. */
5
+ interface DependencyWork {
6
+ kind: DependencyKind;
7
+ target: string;
8
+ calls: number;
9
+ ms: number;
10
+ maxMs: number;
11
+ errors: number;
12
+ }
13
+ //#endregion
2
14
  //#region src/routes.d.ts
3
15
  type Method = Endpoint["method"];
4
16
  /** Route used when the per-interval cardinality cap is hit. */
@@ -19,14 +31,8 @@ declare function routeOf(req: RouteSource): string;
19
31
  declare function heuristicTemplate(url: string): string;
20
32
  //#endregion
21
33
  //#region src/aggregator.d.ts
22
- /** What one finished request did in Postgres, as seen by the instrumented driver. */
23
- interface QueryWork {
24
- queries: number;
25
- queryMs: number;
26
- queryMaxMs: number;
27
- }
28
34
  interface Recorder {
29
- record(method: Method, route: string, status: number, ms: number, work?: QueryWork | undefined): void;
35
+ record(method: Method, route: string, status: number, ms: number, work?: Map<string, DependencyWork> | undefined): void;
30
36
  rotate(): Interval | null;
31
37
  }
32
38
  declare const DEFAULT_MAX_ROUTES = 500;
@@ -42,7 +48,7 @@ declare class IntervalAggregator implements Recorder {
42
48
  private readonly now;
43
49
  constructor(maxRoutes?: number, now?: () => number);
44
50
  get size(): number;
45
- record(method: Method, route: string, status: number, ms: number, work?: QueryWork | undefined): void;
51
+ record(method: Method, route: string, status: number, ms: number, work?: Map<string, DependencyWork> | undefined): void;
46
52
  /** Closes the current interval and starts a new one. Returns null when nothing was recorded. */
47
53
  rotate(): Interval | null;
48
54
  }
@@ -148,7 +154,10 @@ declare class Agent {
148
154
  private readonly handleSignals;
149
155
  private readonly starts;
150
156
  private readonly contexts;
157
+ private readonly runtime;
151
158
  private instrumented;
159
+ private stopHttp;
160
+ private stopRedis;
152
161
  private timer;
153
162
  private started;
154
163
  private recorded;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as createAgent, c as Sender, d as IntervalAggregator, f as OTHER_ROUTE, h as routeOf, i as Agent, l as createLogger, m as normalizeMethod, n as configFromEnv, o as AGENT_VERSION, p as heuristicTemplate, r as detectVersion, s as DEFAULT_MAX_QUEUED, t as DEFAULT_INTERVAL_MS, u as DEFAULT_MAX_ROUTES } from "./config-B_GsH0f7.js";
1
+ import { a as createAgent, c as Sender, d as IntervalAggregator, f as OTHER_ROUTE, h as routeOf, i as Agent, l as createLogger, m as normalizeMethod, n as configFromEnv, o as AGENT_VERSION, p as heuristicTemplate, r as detectVersion, s as DEFAULT_MAX_QUEUED, t as DEFAULT_INTERVAL_MS, u as DEFAULT_MAX_ROUTES } from "./config-Dai_3scM.js";
2
2
  export { AGENT_VERSION, Agent, DEFAULT_INTERVAL_MS, DEFAULT_MAX_QUEUED, DEFAULT_MAX_ROUTES, IntervalAggregator, OTHER_ROUTE, Sender, configFromEnv, createAgent, createLogger, detectVersion, heuristicTemplate, normalizeMethod, routeOf };
package/dist/register.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as createAgent, l as createLogger, n as configFromEnv } from "./config-B_GsH0f7.js";
1
+ import { a as createAgent, l as createLogger, n as configFromEnv } from "./config-Dai_3scM.js";
2
2
  //#region src/register.ts
3
3
  /**
4
4
  * Entry point users load with `node --import @downtrace/agent/register`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@downtrace/agent",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Downtrace agent for Node.js: a flight recorder for your backend. Observes HTTP requests, aggregates locally, ships compact batches, never in your request path.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -22,7 +22,7 @@
22
22
  "node": ">=20"
23
23
  },
24
24
  "dependencies": {
25
- "@downtrace/protocol": "0.2.1"
25
+ "@downtrace/protocol": "0.3.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/express": "^5.0.6",