@tracepanel/js 0.3.1 → 0.3.3
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 +19 -1
- package/dist/api.d.ts +12 -0
- package/dist/api.js +24 -1
- package/dist/api.js.map +1 -1
- package/dist/bun.js +8 -2
- package/dist/bun.js.map +1 -1
- package/dist/explain.js +16 -4
- package/dist/explain.js.map +1 -1
- package/dist/fetch.d.ts +8 -0
- package/dist/fetch.js +27 -0
- package/dist/fetch.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/outgoing.d.ts +10 -0
- package/dist/outgoing.js +145 -0
- package/dist/outgoing.js.map +1 -0
- package/dist/processor.d.ts +13 -2
- package/dist/processor.js +36 -4
- package/dist/processor.js.map +1 -1
- package/dist/setup.js +16 -2
- package/dist/setup.js.map +1 -1
- package/dist/stack.d.ts +1 -1
- package/dist/stack.js +98 -5
- package/dist/stack.js.map +1 -1
- package/dist/transactions.d.ts +19 -0
- package/dist/transactions.js +227 -0
- package/dist/transactions.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -216,9 +216,13 @@ page's, such as a dev server's client.
|
|
|
216
216
|
- SQL from `pg` and `mysql2` (and so Drizzle, Knex, Sequelize, TypeORM and
|
|
217
217
|
Prisma's driver adapters), with the line of your code that ran each
|
|
218
218
|
statement. Prisma's operations show as steps.
|
|
219
|
+
- Transactions: BEGIN … COMMIT (or ROLLBACK) on a `pg` client or a `mysql2`
|
|
220
|
+
connection, with its statements and the calls made inside it, and its
|
|
221
|
+
savepoints.
|
|
219
222
|
- Redis commands (`ioredis`, `redis`) and MongoDB commands, with their own
|
|
220
223
|
N+1 and duplicates.
|
|
221
|
-
- Outgoing HTTP calls: `fetch()`, and `node:http` clients such as axios
|
|
224
|
+
- Outgoing HTTP calls: `fetch()`, and `node:http` clients such as axios, on
|
|
225
|
+
Node and on Bun.
|
|
222
226
|
- BullMQ: each job a worker runs is a task, each job the app adds a step.
|
|
223
227
|
- `console` calls made during a request, and Nest's `Logger`.
|
|
224
228
|
- Errors thrown in a handler, with your frames and their source.
|
|
@@ -240,6 +244,20 @@ request it is a step. `span()` is a step of the current trace. Outside
|
|
|
240
244
|
development they run the function and nothing else. Run a script with
|
|
241
245
|
`npx tracepanel run node script.js`.
|
|
242
246
|
|
|
247
|
+
## The signed-in user
|
|
248
|
+
|
|
249
|
+
```js
|
|
250
|
+
import { setUser } from "@tracepanel/js";
|
|
251
|
+
|
|
252
|
+
setUser({ id: customer.id, username: customer.email });
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Call `setUser()` where the app knows who is signed in, such as its auth
|
|
256
|
+
middleware. The request's trace gets `user.id`, and `user.username` and
|
|
257
|
+
`user.email` when given, as the Python SDK records them. `setUser(null)`
|
|
258
|
+
marks a request nobody signed in to. The username and email stay on your
|
|
259
|
+
machine. Outside a trace it does nothing.
|
|
260
|
+
|
|
243
261
|
## Settings
|
|
244
262
|
|
|
245
263
|
Environment variables, as in the Python SDK:
|
package/dist/api.d.ts
CHANGED
|
@@ -9,3 +9,15 @@ export interface TraceOptions {
|
|
|
9
9
|
export declare function trace<T>(name: string, fn: () => T | Promise<T>, options?: TraceOptions): Promise<Awaited<T>>;
|
|
10
10
|
/** Runs the function as a step of the current trace, with its SQL, calls and logs inside it. */
|
|
11
11
|
export declare function span<T>(name: string, fn: () => T | Promise<T>, attrs?: Attributes): Promise<Awaited<T>>;
|
|
12
|
+
/** The signed-in user, as the Python SDK names one: `user.id`, and the username and email if the app gives them. */
|
|
13
|
+
export interface User {
|
|
14
|
+
id: string | number;
|
|
15
|
+
username?: string;
|
|
16
|
+
email?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Names the signed-in user on the current trace (`null`: nobody is signed in), so the console shows whose request
|
|
20
|
+
* it was and finds a user's traces. The username and email stay on this machine: the agent drops them before
|
|
21
|
+
* anything leaves it.
|
|
22
|
+
*/
|
|
23
|
+
export declare function setUser(user: User | null): void;
|
package/dist/api.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
// The app's own steps and traces. Outside development, and outside a trace, these run
|
|
1
|
+
// The app's own steps and traces, and who the request is for. Outside development, and outside a trace, these run
|
|
2
|
+
// the function and nothing else.
|
|
2
3
|
//
|
|
3
4
|
// await trace("rebuild index", async () => {
|
|
4
5
|
// await span("load rows", () => loadRows());
|
|
5
6
|
// });
|
|
7
|
+
// setUser({ id: customer.id, username: customer.email });
|
|
6
8
|
import { trace as otel, SpanKind, SpanStatusCode } from "@opentelemetry/api";
|
|
7
9
|
const tracer = otel.getTracer("tracepanel");
|
|
8
10
|
async function run(name, attributes, kind, fn) {
|
|
@@ -31,4 +33,25 @@ export function trace(name, fn, options = {}) {
|
|
|
31
33
|
export function span(name, fn, attrs = {}) {
|
|
32
34
|
return run(name, attrs, SpanKind.INTERNAL, fn);
|
|
33
35
|
}
|
|
36
|
+
const RUNTIME = Symbol.for("tracepanel.runtime");
|
|
37
|
+
/**
|
|
38
|
+
* Names the signed-in user on the current trace (`null`: nobody is signed in), so the console shows whose request
|
|
39
|
+
* it was and finds a user's traces. The username and email stay on this machine: the agent drops them before
|
|
40
|
+
* anything leaves it.
|
|
41
|
+
*/
|
|
42
|
+
export function setUser(user) {
|
|
43
|
+
// From the process's Tracepanel on globalThis: code bundled apart from the SDK (a Next.js route) reaches it too.
|
|
44
|
+
const tracepanel = globalThis[RUNTIME];
|
|
45
|
+
if (!tracepanel)
|
|
46
|
+
return;
|
|
47
|
+
if (user === null) {
|
|
48
|
+
tracepanel.processor.setTraceAttrs({ "user.id": null });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
tracepanel.processor.setTraceAttrs({
|
|
52
|
+
"user.id": String(user.id),
|
|
53
|
+
...(user.username === undefined ? {} : { "user.username": user.username }),
|
|
54
|
+
...(user.email === undefined ? {} : { "user.email": user.email }),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
34
57
|
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,kHAAkH;AAClH,iCAAiC;AACjC,EAAE;AACF,+CAA+C;AAC/C,iDAAiD;AACjD,QAAQ;AACR,4DAA4D;AAE5D,OAAO,EAAmB,KAAK,IAAI,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAG9F,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;AAE5C,KAAK,UAAU,GAAG,CAChB,IAAY,EACZ,UAAsB,EACtB,IAAc,EACd,EAAwB;IAExB,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,EAAuB,EAAE;QAC/F,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,eAAe,CAAC,KAAc,CAAC,CAAC;YACxC,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC;YAClD,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AASD,kHAAkH;AAClH,MAAM,UAAU,KAAK,CAAI,IAAY,EAAE,EAAwB,EAAE,OAAO,GAAiB,EAAE;IACzF,IAAI,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,iBAAiB,EAAE,OAAO,CAAC,IAAI,IAAI,SAAS,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC/G,OAAO,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,IAAI,CAAI,IAAY,EAAE,EAAwB,EAAE,KAAK,GAAe,EAAE;IACpF,OAAO,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACjD,CAAC;AASD,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;AAEjD;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,IAAiB;IACvC,iHAAiH;IACjH,MAAM,UAAU,GAAI,UAAsC,CAAC,OAAO,CAAC,CAAC;IACpE,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,UAAU,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,OAAO;IACT,CAAC;IACD,UAAU,CAAC,SAAS,CAAC,aAAa,CAAC;QACjC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC1E,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;KAClE,CAAC,CAAC;AACL,CAAC"}
|
package/dist/bun.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// serve({ routes: { "/api/books/:id": (req) => ... }, fetch: (req) => ... });
|
|
6
6
|
//
|
|
7
7
|
// Start the app with `bun --preload @tracepanel/js/register server.ts` so the database driver is hooked as it loads.
|
|
8
|
-
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
8
|
+
import { propagation, ROOT_CONTEXT, SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
9
9
|
import { start } from "./setup.js";
|
|
10
10
|
import { exposedHeaders, inject } from "./widget.js";
|
|
11
11
|
const tracer = trace.getTracer("tracepanel-bun");
|
|
@@ -32,7 +32,13 @@ export function withTracepanel(handler, route, onError) {
|
|
|
32
32
|
...(route ? { "http.route": route } : {}),
|
|
33
33
|
};
|
|
34
34
|
const startedMs = performance.now();
|
|
35
|
-
|
|
35
|
+
// The caller's traceparent, as Node's http instrumentation reads it: the agent links the caller's trace to this.
|
|
36
|
+
const caller = propagation.extract(ROOT_CONTEXT, request.headers, {
|
|
37
|
+
get: (headers, key) => headers.get(key) ?? undefined,
|
|
38
|
+
keys: (headers) => [...headers.keys()],
|
|
39
|
+
});
|
|
40
|
+
const options = { kind: SpanKind.SERVER, attributes };
|
|
41
|
+
return tracer.startActiveSpan(`${request.method}`, options, caller, async (span) => {
|
|
36
42
|
tracepanel.processor.setFramework("Bun.serve");
|
|
37
43
|
try {
|
|
38
44
|
let response;
|
package/dist/bun.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun.js","sourceRoot":"","sources":["../src/bun.ts"],"names":[],"mappings":"AAAA,oHAAoH;AACpH,uGAAuG;AACvG,EAAE;AACF,gDAAgD;AAChD,gFAAgF;AAChF,EAAE;AACF,qHAAqH;AAErH,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"bun.js","sourceRoot":"","sources":["../src/bun.ts"],"names":[],"mappings":"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"}
|
package/dist/explain.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
// The app's databases are the ones its queries ran on: each pg or mysql2 connection that queries is remembered by
|
|
5
5
|
// its settings (the password among them), and EXPLAIN opens one of its own with them, so it never runs inside the
|
|
6
6
|
// app's transaction. Whatever EXPLAIN ANALYZE does is rolled back.
|
|
7
|
-
import { InstrumentationBase, InstrumentationNodeModuleDefinition } from "@opentelemetry/instrumentation";
|
|
7
|
+
import { InstrumentationBase, InstrumentationNodeModuleDefinition, InstrumentationNodeModuleFile, } from "@opentelemetry/instrumentation";
|
|
8
|
+
import { commonJs } from "./transactions.js";
|
|
8
9
|
const DATABASES = new Map();
|
|
9
10
|
function remember(database) {
|
|
10
11
|
const key = `${database.vendor} ${database.server}:${database.port}/${database.database}`;
|
|
@@ -35,6 +36,8 @@ export async function explain(request) {
|
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
const MARK = Symbol.for("tracepanel.explain");
|
|
39
|
+
/** Nothing to undo: the watchers stay, and only note connections. */
|
|
40
|
+
const keep = (exports) => exports;
|
|
38
41
|
/** Records pg's and mysql2's connections as they query: where they are, and their settings. */
|
|
39
42
|
export class DatabasesInstrumentation extends InstrumentationBase {
|
|
40
43
|
constructor() {
|
|
@@ -43,11 +46,20 @@ export class DatabasesInstrumentation extends InstrumentationBase {
|
|
|
43
46
|
init() {
|
|
44
47
|
return [
|
|
45
48
|
new InstrumentationNodeModuleDefinition("pg", [">=8"], (exports) => {
|
|
46
|
-
this.watch(exports
|
|
49
|
+
this.watch(commonJs(exports)?.Client?.prototype, (client) => rememberPg(client));
|
|
47
50
|
return exports;
|
|
48
|
-
}
|
|
51
|
+
}, keep, [
|
|
52
|
+
// pg imported by its ES module's file URL (Nitro's dev server) loads without the hook above: its client
|
|
53
|
+
// class is watched as it loads, once the file's other hooks are done.
|
|
54
|
+
new InstrumentationNodeModuleFile("pg/lib/client.js", [">=8"], (exports) => {
|
|
55
|
+
const proto = commonJs(exports)?.prototype;
|
|
56
|
+
queueMicrotask(() => this.watch(proto, (client) => rememberPg(client)));
|
|
57
|
+
return exports;
|
|
58
|
+
}, keep),
|
|
59
|
+
]),
|
|
49
60
|
new InstrumentationNodeModuleDefinition("mysql2", [">=3"], (exports) => {
|
|
50
|
-
|
|
61
|
+
const mysql2 = commonJs(exports);
|
|
62
|
+
this.watch(mysql2?.Connection?.prototype, (client) => rememberMysql(client, mysql2));
|
|
51
63
|
return exports;
|
|
52
64
|
}),
|
|
53
65
|
];
|
package/dist/explain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../src/explain.ts"],"names":[],"mappings":"AAAA,oHAAoH;AACpH,6GAA6G;AAC7G,EAAE;AACF,kHAAkH;AAClH,kHAAkH;AAClH,mEAAmE;AAEnE,OAAO,
|
|
1
|
+
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../src/explain.ts"],"names":[],"mappings":"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"}
|
package/dist/fetch.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The app's line that made the call (`file:line in function`), in the context of the call. */
|
|
2
|
+
export declare const CALL_ORIGIN: symbol;
|
|
3
|
+
type Fetch = (...args: never[]) => Promise<Response>;
|
|
4
|
+
/** The fetch, taking the app's line as it is called. */
|
|
5
|
+
export declare function wrapFetch<F extends Fetch>(fetch: F, root: string): F;
|
|
6
|
+
/** globalThis.fetch, wrapped once per process. */
|
|
7
|
+
export declare function traceFetch(root: string): void;
|
|
8
|
+
export {};
|
package/dist/fetch.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// fetch() as the app calls it. Node's undici starts the call's span from inside fetch, where none of the app's code is
|
|
2
|
+
// on the stack: the app's line is taken here, as the call is made, and handed to the span in its context.
|
|
3
|
+
import { context, createContextKey, trace } from "@opentelemetry/api";
|
|
4
|
+
import { origin } from "./stack.js";
|
|
5
|
+
/** The app's line that made the call (`file:line in function`), in the context of the call. */
|
|
6
|
+
export const CALL_ORIGIN = createContextKey("tracepanel.call_origin");
|
|
7
|
+
const WRAPPED = Symbol.for("tracepanel.fetch");
|
|
8
|
+
/** The fetch, taking the app's line as it is called. */
|
|
9
|
+
export function wrapFetch(fetch, root) {
|
|
10
|
+
if (fetch[WRAPPED])
|
|
11
|
+
return fetch;
|
|
12
|
+
const wrapped = function (...args) {
|
|
13
|
+
const found = trace.getActiveSpan() ? origin(root) : null;
|
|
14
|
+
if (!found)
|
|
15
|
+
return fetch.apply(this, args);
|
|
16
|
+
return context.with(context.active().setValue(CALL_ORIGIN, found), () => fetch.apply(this, args));
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(wrapped, WRAPPED, { value: true });
|
|
19
|
+
return wrapped;
|
|
20
|
+
}
|
|
21
|
+
/** globalThis.fetch, wrapped once per process. */
|
|
22
|
+
export function traceFetch(root) {
|
|
23
|
+
if (typeof globalThis.fetch !== "function")
|
|
24
|
+
return;
|
|
25
|
+
globalThis.fetch = wrapFetch(globalThis.fetch, root);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAAA,uHAAuH;AACvH,0GAA0G;AAE1G,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,+FAA+F;AAC/F,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAC,wBAAwB,CAAC,CAAC;AAEtE,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAI/C,wDAAwD;AACxD,MAAM,UAAU,SAAS,CAAkB,KAAQ,EAAE,IAAY;IAC/D,IAAK,KAAiC,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,OAAO,GAAG,UAAyB,GAAG,IAAmB;QAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1D,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3C,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACpG,CAAC,CAAC;IACF,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,OAAO,OAAuB,CAAC;AACjC,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,OAAO,UAAU,CAAC,KAAK,KAAK,UAAU;QAAE,OAAO;IACnD,UAAU,CAAC,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACvD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { TraceOptions } from "./api.js";
|
|
2
|
-
export { span, trace } from "./api.js";
|
|
1
|
+
export type { TraceOptions, User } from "./api.js";
|
|
2
|
+
export { setUser, span, trace } from "./api.js";
|
|
3
3
|
export type { Config, Thresholds } from "./config.js";
|
|
4
4
|
export { loadConfig } from "./config.js";
|
|
5
5
|
export type { Trace } from "./model.js";
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { request as httpRequest } from "node:http";
|
|
2
|
+
type Fetch = typeof globalThis.fetch;
|
|
3
|
+
/** fetch(), each call an http.client span with the traceparent in its headers. */
|
|
4
|
+
export declare function tracedFetch(fetch: Fetch): Fetch;
|
|
5
|
+
type HttpRequest = typeof httpRequest;
|
|
6
|
+
/** node:http's (or https's) request(): each call an http.client span, its traceparent a header of the request. */
|
|
7
|
+
export declare function tracedRequest(request: HttpRequest, scheme: "http" | "https"): HttpRequest;
|
|
8
|
+
/** Bun's fetch and node:http/https, traced: what the undici and http instrumentations do on Node. */
|
|
9
|
+
export declare function traceBunCalls(): void;
|
|
10
|
+
export {};
|
package/dist/outgoing.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Outgoing HTTP on Bun. Node's instrumentations see fetch() through undici's diagnostics channel and node:http by
|
|
2
|
+
// patching the module as it loads; Bun's fetch has no such channel and its node:http is built in. Here both make the
|
|
3
|
+
// same http.client span as on Node, and send its W3C traceparent, so the callee's trace links to it.
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { context, propagation, SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
6
|
+
const tracer = trace.getTracer("tracepanel-outgoing");
|
|
7
|
+
const WRAPPED = Symbol.for("tracepanel.outgoing");
|
|
8
|
+
function attributes(method, url) {
|
|
9
|
+
return {
|
|
10
|
+
"http.request.method": method,
|
|
11
|
+
"url.full": url.href,
|
|
12
|
+
"url.scheme": url.protocol.replace(":", ""),
|
|
13
|
+
"server.address": url.hostname,
|
|
14
|
+
"server.port": url.port ? Number(url.port) : url.protocol === "https:" ? 443 : 80,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function marked(wrapped) {
|
|
18
|
+
Object.defineProperty(wrapped, WRAPPED, { value: true });
|
|
19
|
+
return wrapped;
|
|
20
|
+
}
|
|
21
|
+
function failed(span, error) {
|
|
22
|
+
span.recordException(error instanceof Error ? error : new Error(String(error)));
|
|
23
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
24
|
+
}
|
|
25
|
+
/** fetch(), each call an http.client span with the traceparent in its headers. */
|
|
26
|
+
export function tracedFetch(fetch) {
|
|
27
|
+
if (fetch[WRAPPED])
|
|
28
|
+
return fetch;
|
|
29
|
+
const traced = async function (input, init) {
|
|
30
|
+
if (!trace.getActiveSpan())
|
|
31
|
+
return fetch.call(this, input, init);
|
|
32
|
+
const request = input instanceof Request ? input : undefined;
|
|
33
|
+
let url;
|
|
34
|
+
try {
|
|
35
|
+
url = new URL(request ? request.url : String(input));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return fetch.call(this, input, init);
|
|
39
|
+
}
|
|
40
|
+
const method = (init?.method ?? request?.method ?? "GET").toUpperCase();
|
|
41
|
+
const span = tracer.startSpan(method, { kind: SpanKind.CLIENT, attributes: attributes(method, url) });
|
|
42
|
+
const inside = trace.setSpan(context.active(), span);
|
|
43
|
+
const headers = new Headers(init?.headers ?? request?.headers);
|
|
44
|
+
propagation.inject(inside, headers, { set: (carrier, key, value) => carrier.set(key, value) });
|
|
45
|
+
try {
|
|
46
|
+
const response = await context.with(inside, () => fetch.call(this, input, { ...init, headers }));
|
|
47
|
+
span.setAttribute("http.response.status_code", response.status);
|
|
48
|
+
if (response.status >= 500)
|
|
49
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
50
|
+
return response;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
failed(span, error);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
span.end();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return marked(Object.assign(traced, fetch));
|
|
61
|
+
}
|
|
62
|
+
/** Where a node:http request goes: request(url, options?, callback?) or request(options, callback?). */
|
|
63
|
+
function target(args, scheme) {
|
|
64
|
+
try {
|
|
65
|
+
const [first, second] = args;
|
|
66
|
+
const given = typeof first === "string" || first instanceof URL ? new URL(first) : undefined;
|
|
67
|
+
const options = (given ? (typeof second === "object" && second ? second : {}) : (first ?? {}));
|
|
68
|
+
const method = String(options.method ?? "GET").toUpperCase();
|
|
69
|
+
if (given)
|
|
70
|
+
return { method, url: given };
|
|
71
|
+
const host = options.hostname ?? options.host ?? "localhost";
|
|
72
|
+
const port = options.port ? `:${options.port}` : "";
|
|
73
|
+
const protocol = options.protocol ?? `${scheme}:`;
|
|
74
|
+
return { method, url: new URL(`${protocol}//${host}${port}${options.path ?? "/"}`) };
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** node:http's (or https's) request(): each call an http.client span, its traceparent a header of the request. */
|
|
81
|
+
export function tracedRequest(request, scheme) {
|
|
82
|
+
if (request[WRAPPED])
|
|
83
|
+
return request;
|
|
84
|
+
const send = request;
|
|
85
|
+
const traced = function (...args) {
|
|
86
|
+
const found = trace.getActiveSpan() ? target(args, scheme) : undefined;
|
|
87
|
+
if (!found)
|
|
88
|
+
return send.apply(this, args);
|
|
89
|
+
const span = tracer.startSpan(found.method, {
|
|
90
|
+
kind: SpanKind.CLIENT,
|
|
91
|
+
attributes: attributes(found.method, found.url),
|
|
92
|
+
});
|
|
93
|
+
const inside = trace.setSpan(context.active(), span);
|
|
94
|
+
const sent = context.with(inside, () => send.apply(this, args));
|
|
95
|
+
let ended = false;
|
|
96
|
+
const end = () => {
|
|
97
|
+
if (ended)
|
|
98
|
+
return;
|
|
99
|
+
ended = true;
|
|
100
|
+
span.end();
|
|
101
|
+
};
|
|
102
|
+
try {
|
|
103
|
+
propagation.inject(inside, sent, { set: (carrier, key, value) => carrier.setHeader(key, value) });
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// The headers went out already: the call is recorded all the same.
|
|
107
|
+
}
|
|
108
|
+
sent.once("response", (response) => {
|
|
109
|
+
span.setAttribute("http.response.status_code", response.statusCode ?? 0);
|
|
110
|
+
if ((response.statusCode ?? 0) >= 500)
|
|
111
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
112
|
+
response.once("end", end);
|
|
113
|
+
response.once("close", end);
|
|
114
|
+
});
|
|
115
|
+
sent.once("error", (error) => {
|
|
116
|
+
failed(span, error);
|
|
117
|
+
end();
|
|
118
|
+
});
|
|
119
|
+
sent.once("close", end);
|
|
120
|
+
return sent;
|
|
121
|
+
};
|
|
122
|
+
return marked(traced);
|
|
123
|
+
}
|
|
124
|
+
/** get(): request() that ends the request itself, as node:http's does. */
|
|
125
|
+
function tracedGet(request) {
|
|
126
|
+
const send = request;
|
|
127
|
+
return marked(function (...args) {
|
|
128
|
+
const sent = send.apply(this, args);
|
|
129
|
+
sent.end();
|
|
130
|
+
return sent;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/** Bun's fetch and node:http/https, traced: what the undici and http instrumentations do on Node. */
|
|
134
|
+
export function traceBunCalls() {
|
|
135
|
+
globalThis.fetch = tracedFetch(globalThis.fetch);
|
|
136
|
+
const require = createRequire(import.meta.url);
|
|
137
|
+
for (const scheme of ["http", "https"]) {
|
|
138
|
+
const target = require(`node:${scheme}`);
|
|
139
|
+
if (target.request[WRAPPED])
|
|
140
|
+
continue;
|
|
141
|
+
target.request = tracedRequest(target.request, scheme);
|
|
142
|
+
target.get = tracedGet(target.request);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=outgoing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outgoing.js","sourceRoot":"","sources":["../src/outgoing.ts"],"names":[],"mappings":"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"}
|
package/dist/processor.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Context } from "@opentelemetry/api";
|
|
2
2
|
import type { ReadableSpan, Span as SdkSpan, SpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
3
3
|
import type { Config } from "./config.js";
|
|
4
|
-
import { type Log, micros, type Trace } from "./model.js";
|
|
4
|
+
import { type Attrs, type Log, micros, type Trace } from "./model.js";
|
|
5
5
|
/** Where a trace goes once its request ends. */
|
|
6
6
|
export interface Sink {
|
|
7
7
|
submit(trace: Trace): void;
|
|
@@ -33,6 +33,10 @@ interface Building {
|
|
|
33
33
|
replaced: Set<string>;
|
|
34
34
|
/** OTel span id: the Express route handlers' ones, so a Nest span under one can take its place. */
|
|
35
35
|
expressHandlers: Set<string>;
|
|
36
|
+
/** OTel span ids of transaction and savepoint spans. */
|
|
37
|
+
transactions: Set<string>;
|
|
38
|
+
/** OTel span id → the app's line behind a span that is left out, for the span it stands over (Next's fetch). */
|
|
39
|
+
passedOrigins: Map<string, string | null>;
|
|
36
40
|
/**
|
|
37
41
|
* The app's line behind the latest span that had one. A driver often starts its query span later, from a callback
|
|
38
42
|
* (pg's pool runs the query once it has a connection), where the stack holds none of the app's code; the
|
|
@@ -51,8 +55,13 @@ export declare class TracepanelProcessor implements SpanProcessor {
|
|
|
51
55
|
*/
|
|
52
56
|
private readonly owner;
|
|
53
57
|
constructor(config: Config, sink: Sink);
|
|
54
|
-
onStart(span: SdkSpan,
|
|
58
|
+
onStart(span: SdkSpan, parentContext: Context): void;
|
|
55
59
|
onEnd(span: ReadableSpan): void;
|
|
60
|
+
/**
|
|
61
|
+
* BEGIN, COMMIT and the like in a transaction span, which stands for them. Told as the span ends: the pg
|
|
62
|
+
* instrumentation sets the statement after it starts.
|
|
63
|
+
*/
|
|
64
|
+
private control;
|
|
56
65
|
forceFlush(): Promise<void>;
|
|
57
66
|
shutdown(): Promise<void>;
|
|
58
67
|
/** The trace being built for the active request, with the current span's Tracepanel id. */
|
|
@@ -80,6 +89,8 @@ export declare class TracepanelProcessor implements SpanProcessor {
|
|
|
80
89
|
setFramework(name: string): void;
|
|
81
90
|
/** The route pattern the framework matched, when the root span doesn't carry one (Nitro). */
|
|
82
91
|
setRoute(route: string): void;
|
|
92
|
+
/** Attributes of the active request's trace: the signed-in user (setUser()). */
|
|
93
|
+
setTraceAttrs(attrs: Attrs): void;
|
|
83
94
|
/** The framework the active request ran on, as the panel shows it. */
|
|
84
95
|
framework(): string | undefined;
|
|
85
96
|
private start;
|
package/dist/processor.js
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
5
5
|
import { httpCall, isMongo, isRedis, mongoCall, redisCall } from "./calls.js";
|
|
6
|
+
import { CALL_ORIGIN } from "./fetch.js";
|
|
6
7
|
import { withVersion } from "./frameworks.js";
|
|
7
8
|
import { countDropped, limited, MAX_LOGS, micros, newId, } from "./model.js";
|
|
8
9
|
import { fingerprint, spanName, statement } from "./sql.js";
|
|
9
10
|
import { frames, origin } from "./stack.js";
|
|
11
|
+
import { CONTROL } from "./transactions.js";
|
|
10
12
|
// A request's span can end after the response does (Express ends an async handler's span when its promise settles):
|
|
11
13
|
// the trace goes out this long after the request's span ends, with the spans that ended meanwhile.
|
|
12
14
|
const LATE_SPANS_MS = 25;
|
|
@@ -27,6 +29,8 @@ const SKIPPED_NEXT = new Set([
|
|
|
27
29
|
"LoadComponents.loadRouteModule",
|
|
28
30
|
"RouteModule.prepare",
|
|
29
31
|
"ResolveMetadata.generateMetadata",
|
|
32
|
+
// Next's own span of a fetch(): undici's under it is the call, with the traceparent the callee got.
|
|
33
|
+
"AppRender.fetch",
|
|
30
34
|
]);
|
|
31
35
|
// What runs a Next.js route: an app or pages render, a route handler, getServerSideProps.
|
|
32
36
|
const NEXT_HANDLERS = new Set([
|
|
@@ -83,7 +87,7 @@ export class TracepanelProcessor {
|
|
|
83
87
|
this.config = config;
|
|
84
88
|
this.sink = sink;
|
|
85
89
|
}
|
|
86
|
-
onStart(span,
|
|
90
|
+
onStart(span, parentContext) {
|
|
87
91
|
const context = span.spanContext();
|
|
88
92
|
const parent = span.parentSpanContext;
|
|
89
93
|
let building = parent ? this.owner.get(parent.spanId) : undefined;
|
|
@@ -111,11 +115,14 @@ export class TracepanelProcessor {
|
|
|
111
115
|
const found = origin(this.config.root);
|
|
112
116
|
if (found)
|
|
113
117
|
building.lastOrigin = found;
|
|
118
|
+
const attrs = attrsOf(span);
|
|
114
119
|
if (!local && parent && skipped(span)) {
|
|
115
120
|
building.ids.set(context.spanId, building.ids.get(parent.spanId) ?? null);
|
|
121
|
+
building.passedOrigins.set(context.spanId, found ?? building.passedOrigins.get(parent.spanId) ?? null);
|
|
116
122
|
return;
|
|
117
123
|
}
|
|
118
|
-
|
|
124
|
+
if (attrs["tracepanel.span_kind"] === "transaction")
|
|
125
|
+
building.transactions.add(context.spanId);
|
|
119
126
|
if (attrs["express.type"] === "request_handler")
|
|
120
127
|
building.expressHandlers.add(context.spanId);
|
|
121
128
|
if (parent && attrs["nestjs.type"] === "request_context" && building.expressHandlers.has(parent.spanId)) {
|
|
@@ -128,7 +135,11 @@ export class TracepanelProcessor {
|
|
|
128
135
|
if (!parent && attrs["next.span_type"] === "BaseServer.handleRequest")
|
|
129
136
|
building.framework = "Next.js";
|
|
130
137
|
building.ids.set(context.spanId, newId());
|
|
131
|
-
|
|
138
|
+
// A span started outside the app's code (undici's, under Next's fetch span) is the call the app made there.
|
|
139
|
+
// So is one a call made from its context, which took the app's line as the app called it (fetch()).
|
|
140
|
+
const passed = (parent ? building.passedOrigins.get(parent.spanId) : undefined) ??
|
|
141
|
+
parentContext.getValue(CALL_ORIGIN);
|
|
142
|
+
building.origins.set(context.spanId, found ?? passed ?? building.lastOrigin);
|
|
132
143
|
}
|
|
133
144
|
onEnd(span) {
|
|
134
145
|
if (process.env.TRACEPANEL_DEBUG) {
|
|
@@ -141,7 +152,7 @@ export class TracepanelProcessor {
|
|
|
141
152
|
const root = context.spanId === building.rootSpanId;
|
|
142
153
|
if (building.replaced.has(context.spanId))
|
|
143
154
|
return;
|
|
144
|
-
if (root || !skipped(span))
|
|
155
|
+
if (root || !(skipped(span) || this.control(building, span)))
|
|
145
156
|
this.convert(building, span, root);
|
|
146
157
|
if (!root)
|
|
147
158
|
return;
|
|
@@ -151,6 +162,14 @@ export class TracepanelProcessor {
|
|
|
151
162
|
this.sink.submit(limited(building.trace));
|
|
152
163
|
}, LATE_SPANS_MS).unref();
|
|
153
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* BEGIN, COMMIT and the like in a transaction span, which stands for them. Told as the span ends: the pg
|
|
167
|
+
* instrumentation sets the statement after it starts.
|
|
168
|
+
*/
|
|
169
|
+
control(building, span) {
|
|
170
|
+
const parent = span.parentSpanContext?.spanId;
|
|
171
|
+
return parent !== undefined && building.transactions.has(parent) && CONTROL.test(statementOf(attrsOf(span)));
|
|
172
|
+
}
|
|
154
173
|
forceFlush() {
|
|
155
174
|
return Promise.resolve();
|
|
156
175
|
}
|
|
@@ -247,6 +266,12 @@ export class TracepanelProcessor {
|
|
|
247
266
|
if (current)
|
|
248
267
|
current.building.route = route;
|
|
249
268
|
}
|
|
269
|
+
/** Attributes of the active request's trace: the signed-in user (setUser()). */
|
|
270
|
+
setTraceAttrs(attrs) {
|
|
271
|
+
const current = this.current();
|
|
272
|
+
if (current)
|
|
273
|
+
Object.assign(current.building.trace.attrs, attrs);
|
|
274
|
+
}
|
|
250
275
|
/** The framework the active request ran on, as the panel shows it. */
|
|
251
276
|
framework() {
|
|
252
277
|
return this.current()?.building.framework;
|
|
@@ -280,6 +305,8 @@ export class TracepanelProcessor {
|
|
|
280
305
|
replaced: new Set(),
|
|
281
306
|
nestViews: new Set(),
|
|
282
307
|
expressHandlers: new Set(),
|
|
308
|
+
transactions: new Set(),
|
|
309
|
+
passedOrigins: new Map(),
|
|
283
310
|
parents: new Map(),
|
|
284
311
|
lastOrigin: null,
|
|
285
312
|
};
|
|
@@ -333,6 +360,11 @@ export class TracepanelProcessor {
|
|
|
333
360
|
"code.origin": codeOrigin,
|
|
334
361
|
};
|
|
335
362
|
}
|
|
363
|
+
else if (attrs["tracepanel.span_kind"] === "transaction") {
|
|
364
|
+
converted.kind = "transaction";
|
|
365
|
+
const { "tracepanel.span_kind": _, ...own } = attrs;
|
|
366
|
+
converted.attrs = { ...own, "code.origin": codeOrigin };
|
|
367
|
+
}
|
|
336
368
|
else if (isRedis(attrs)) {
|
|
337
369
|
const call = redisCall(attrs, span.name);
|
|
338
370
|
converted.kind = "redis";
|