@wizeworks/lens-node 0.0.0-stage → 0.3.0-alpha.2

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.
Files changed (303) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +65 -2
  3. package/dist/adapters/drizzle.d.ts +7 -0
  4. package/dist/adapters/drizzle.d.ts.map +1 -0
  5. package/dist/adapters/drizzle.js +41 -0
  6. package/dist/adapters/drizzle.js.map +1 -0
  7. package/dist/adapters/mysql2.d.ts +6 -0
  8. package/dist/adapters/mysql2.d.ts.map +1 -0
  9. package/dist/adapters/mysql2.js +60 -0
  10. package/dist/adapters/mysql2.js.map +1 -0
  11. package/dist/adapters/pg.d.ts +6 -0
  12. package/dist/adapters/pg.d.ts.map +1 -0
  13. package/dist/adapters/pg.js +50 -0
  14. package/dist/adapters/pg.js.map +1 -0
  15. package/dist/adapters/prisma.d.ts +22 -0
  16. package/dist/adapters/prisma.d.ts.map +1 -0
  17. package/dist/adapters/prisma.js +48 -0
  18. package/dist/adapters/prisma.js.map +1 -0
  19. package/dist/adapters/registry.d.ts +37 -0
  20. package/dist/adapters/registry.d.ts.map +1 -0
  21. package/dist/adapters/registry.js +41 -0
  22. package/dist/adapters/registry.js.map +1 -0
  23. package/dist/adapters/sqlite.d.ts +10 -0
  24. package/dist/adapters/sqlite.d.ts.map +1 -0
  25. package/dist/adapters/sqlite.js +59 -0
  26. package/dist/adapters/sqlite.js.map +1 -0
  27. package/dist/adapters/typeorm.d.ts +4 -0
  28. package/dist/adapters/typeorm.d.ts.map +1 -0
  29. package/dist/adapters/typeorm.js +43 -0
  30. package/dist/adapters/typeorm.js.map +1 -0
  31. package/dist/api.d.ts +26 -0
  32. package/dist/api.d.ts.map +1 -0
  33. package/dist/api.js +112 -0
  34. package/dist/api.js.map +1 -0
  35. package/dist/body-capture.d.ts +13 -0
  36. package/dist/body-capture.d.ts.map +1 -0
  37. package/dist/body-capture.js +54 -0
  38. package/dist/body-capture.js.map +1 -0
  39. package/dist/capture.d.ts +8 -0
  40. package/dist/capture.d.ts.map +1 -0
  41. package/dist/capture.js +33 -0
  42. package/dist/capture.js.map +1 -0
  43. package/dist/client-spans.d.ts +11 -0
  44. package/dist/client-spans.d.ts.map +1 -0
  45. package/dist/client-spans.js +83 -0
  46. package/dist/client-spans.js.map +1 -0
  47. package/dist/db.d.ts +25 -0
  48. package/dist/db.d.ts.map +1 -0
  49. package/dist/db.js +107 -0
  50. package/dist/db.js.map +1 -0
  51. package/dist/disabled.d.ts +4 -0
  52. package/dist/disabled.d.ts.map +1 -0
  53. package/dist/disabled.js +25 -0
  54. package/dist/disabled.js.map +1 -0
  55. package/dist/expose-headers.d.ts +6 -0
  56. package/dist/expose-headers.d.ts.map +1 -0
  57. package/dist/expose-headers.js +43 -0
  58. package/dist/expose-headers.js.map +1 -0
  59. package/dist/federation.d.ts +7 -0
  60. package/dist/federation.d.ts.map +1 -0
  61. package/dist/federation.js +33 -0
  62. package/dist/federation.js.map +1 -0
  63. package/dist/frameworks/fastify.d.ts +6 -0
  64. package/dist/frameworks/fastify.d.ts.map +1 -0
  65. package/dist/frameworks/fastify.js +60 -0
  66. package/dist/frameworks/fastify.js.map +1 -0
  67. package/dist/frameworks/hono.d.ts +6 -0
  68. package/dist/frameworks/hono.d.ts.map +1 -0
  69. package/dist/frameworks/hono.js +34 -0
  70. package/dist/frameworks/hono.js.map +1 -0
  71. package/dist/frameworks/koa.d.ts +13 -0
  72. package/dist/frameworks/koa.d.ts.map +1 -0
  73. package/dist/frameworks/koa.js +42 -0
  74. package/dist/frameworks/koa.js.map +1 -0
  75. package/dist/frameworks/next.d.ts +25 -0
  76. package/dist/frameworks/next.d.ts.map +1 -0
  77. package/dist/frameworks/next.js +49 -0
  78. package/dist/frameworks/next.js.map +1 -0
  79. package/dist/frameworks/node-server.d.ts +6 -0
  80. package/dist/frameworks/node-server.d.ts.map +1 -0
  81. package/dist/frameworks/node-server.js +35 -0
  82. package/dist/frameworks/node-server.js.map +1 -0
  83. package/dist/grpc/client.d.ts +6 -0
  84. package/dist/grpc/client.d.ts.map +1 -0
  85. package/dist/grpc/client.js +52 -0
  86. package/dist/grpc/client.js.map +1 -0
  87. package/dist/grpc/index.d.ts +4 -0
  88. package/dist/grpc/index.d.ts.map +1 -0
  89. package/dist/grpc/index.js +16 -0
  90. package/dist/grpc/index.js.map +1 -0
  91. package/dist/grpc/server.d.ts +10 -0
  92. package/dist/grpc/server.d.ts.map +1 -0
  93. package/dist/grpc/server.js +98 -0
  94. package/dist/grpc/server.js.map +1 -0
  95. package/dist/grpc/shared.d.ts +40 -0
  96. package/dist/grpc/shared.d.ts.map +1 -0
  97. package/dist/grpc/shared.js +45 -0
  98. package/dist/grpc/shared.js.map +1 -0
  99. package/dist/http-util.d.ts +10 -0
  100. package/dist/http-util.d.ts.map +1 -0
  101. package/dist/http-util.js +47 -0
  102. package/dist/http-util.js.map +1 -0
  103. package/dist/hub-connect.d.ts +10 -0
  104. package/dist/hub-connect.d.ts.map +1 -0
  105. package/dist/hub-connect.js +22 -0
  106. package/dist/hub-connect.js.map +1 -0
  107. package/dist/hub-export.d.ts +34 -0
  108. package/dist/hub-export.d.ts.map +1 -0
  109. package/dist/hub-export.js +135 -0
  110. package/dist/hub-export.js.map +1 -0
  111. package/dist/index.d.ts +35 -0
  112. package/dist/index.d.ts.map +1 -0
  113. package/dist/index.js +27 -0
  114. package/dist/index.js.map +1 -0
  115. package/dist/info.d.ts +18 -0
  116. package/dist/info.d.ts.map +1 -0
  117. package/dist/info.js +31 -0
  118. package/dist/info.js.map +1 -0
  119. package/dist/kit.d.ts +14 -0
  120. package/dist/kit.d.ts.map +1 -0
  121. package/dist/kit.js +12 -0
  122. package/dist/kit.js.map +1 -0
  123. package/dist/logger.d.ts +29 -0
  124. package/dist/logger.d.ts.map +1 -0
  125. package/dist/logger.js +82 -0
  126. package/dist/logger.js.map +1 -0
  127. package/dist/logs/bunyan.d.ts +4 -0
  128. package/dist/logs/bunyan.d.ts.map +1 -0
  129. package/dist/logs/bunyan.js +42 -0
  130. package/dist/logs/bunyan.js.map +1 -0
  131. package/dist/logs/captured.d.ts +4 -0
  132. package/dist/logs/captured.d.ts.map +1 -0
  133. package/dist/logs/captured.js +9 -0
  134. package/dist/logs/captured.js.map +1 -0
  135. package/dist/logs/consola.d.ts +4 -0
  136. package/dist/logs/consola.d.ts.map +1 -0
  137. package/dist/logs/consola.js +25 -0
  138. package/dist/logs/consola.js.map +1 -0
  139. package/dist/logs/console.d.ts +4 -0
  140. package/dist/logs/console.d.ts.map +1 -0
  141. package/dist/logs/console.js +49 -0
  142. package/dist/logs/console.js.map +1 -0
  143. package/dist/logs/levels.d.ts +14 -0
  144. package/dist/logs/levels.d.ts.map +1 -0
  145. package/dist/logs/levels.js +58 -0
  146. package/dist/logs/levels.js.map +1 -0
  147. package/dist/logs/log4js.d.ts +16 -0
  148. package/dist/logs/log4js.d.ts.map +1 -0
  149. package/dist/logs/log4js.js +21 -0
  150. package/dist/logs/log4js.js.map +1 -0
  151. package/dist/logs/nest.d.ts +6 -0
  152. package/dist/logs/nest.d.ts.map +1 -0
  153. package/dist/logs/nest.js +34 -0
  154. package/dist/logs/nest.js.map +1 -0
  155. package/dist/logs/otel.d.ts +24 -0
  156. package/dist/logs/otel.d.ts.map +1 -0
  157. package/dist/logs/otel.js +31 -0
  158. package/dist/logs/otel.js.map +1 -0
  159. package/dist/logs/pino.d.ts +4 -0
  160. package/dist/logs/pino.d.ts.map +1 -0
  161. package/dist/logs/pino.js +86 -0
  162. package/dist/logs/pino.js.map +1 -0
  163. package/dist/logs/winston.d.ts +4 -0
  164. package/dist/logs/winston.d.ts.map +1 -0
  165. package/dist/logs/winston.js +65 -0
  166. package/dist/logs/winston.js.map +1 -0
  167. package/dist/mcp-find.d.ts +5 -0
  168. package/dist/mcp-find.d.ts.map +1 -0
  169. package/dist/mcp-find.js +42 -0
  170. package/dist/mcp-find.js.map +1 -0
  171. package/dist/mcp-metrics.d.ts +5 -0
  172. package/dist/mcp-metrics.d.ts.map +1 -0
  173. package/dist/mcp-metrics.js +77 -0
  174. package/dist/mcp-metrics.js.map +1 -0
  175. package/dist/mcp-shared.d.ts +30 -0
  176. package/dist/mcp-shared.d.ts.map +1 -0
  177. package/dist/mcp-shared.js +5 -0
  178. package/dist/mcp-shared.js.map +1 -0
  179. package/dist/mcp-traces.d.ts +5 -0
  180. package/dist/mcp-traces.d.ts.map +1 -0
  181. package/dist/mcp-traces.js +51 -0
  182. package/dist/mcp-traces.js.map +1 -0
  183. package/dist/mcp.d.ts +6 -0
  184. package/dist/mcp.d.ts.map +1 -0
  185. package/dist/mcp.js +26 -0
  186. package/dist/mcp.js.map +1 -0
  187. package/dist/messaging/amqplib.d.ts +4 -0
  188. package/dist/messaging/amqplib.d.ts.map +1 -0
  189. package/dist/messaging/amqplib.js +89 -0
  190. package/dist/messaging/amqplib.js.map +1 -0
  191. package/dist/messaging/kafkajs.d.ts +4 -0
  192. package/dist/messaging/kafkajs.d.ts.map +1 -0
  193. package/dist/messaging/kafkajs.js +78 -0
  194. package/dist/messaging/kafkajs.js.map +1 -0
  195. package/dist/messaging/servicebus.d.ts +4 -0
  196. package/dist/messaging/servicebus.d.ts.map +1 -0
  197. package/dist/messaging/servicebus.js +85 -0
  198. package/dist/messaging/servicebus.js.map +1 -0
  199. package/dist/messaging/shared.d.ts +30 -0
  200. package/dist/messaging/shared.d.ts.map +1 -0
  201. package/dist/messaging/shared.js +74 -0
  202. package/dist/messaging/shared.js.map +1 -0
  203. package/dist/metrics/exponential.d.ts +17 -0
  204. package/dist/metrics/exponential.d.ts.map +1 -0
  205. package/dist/metrics/exponential.js +12 -0
  206. package/dist/metrics/exponential.js.map +1 -0
  207. package/dist/metrics/gc.d.ts +15 -0
  208. package/dist/metrics/gc.d.ts.map +1 -0
  209. package/dist/metrics/gc.js +44 -0
  210. package/dist/metrics/gc.js.map +1 -0
  211. package/dist/metrics/otel.d.ts +39 -0
  212. package/dist/metrics/otel.d.ts.map +1 -0
  213. package/dist/metrics/otel.js +62 -0
  214. package/dist/metrics/otel.js.map +1 -0
  215. package/dist/metrics/runtime.d.ts +17 -0
  216. package/dist/metrics/runtime.d.ts.map +1 -0
  217. package/dist/metrics/runtime.js +100 -0
  218. package/dist/metrics/runtime.js.map +1 -0
  219. package/dist/metrics/setup.d.ts +13 -0
  220. package/dist/metrics/setup.d.ts.map +1 -0
  221. package/dist/metrics/setup.js +20 -0
  222. package/dist/metrics/setup.js.map +1 -0
  223. package/dist/metrics/store.d.ts +34 -0
  224. package/dist/metrics/store.d.ts.map +1 -0
  225. package/dist/metrics/store.js +94 -0
  226. package/dist/metrics/store.js.map +1 -0
  227. package/dist/mode.d.ts +6 -0
  228. package/dist/mode.d.ts.map +1 -0
  229. package/dist/mode.js +7 -0
  230. package/dist/mode.js.map +1 -0
  231. package/dist/next.d.ts +5 -0
  232. package/dist/next.d.ts.map +1 -0
  233. package/dist/next.js +2 -0
  234. package/dist/next.js.map +1 -0
  235. package/dist/persist-schema.d.ts +14 -0
  236. package/dist/persist-schema.d.ts.map +1 -0
  237. package/dist/persist-schema.js +41 -0
  238. package/dist/persist-schema.js.map +1 -0
  239. package/dist/persist-util.d.ts +4 -0
  240. package/dist/persist-util.d.ts.map +1 -0
  241. package/dist/persist-util.js +30 -0
  242. package/dist/persist-util.js.map +1 -0
  243. package/dist/persist.d.ts +27 -0
  244. package/dist/persist.d.ts.map +1 -0
  245. package/dist/persist.js +159 -0
  246. package/dist/persist.js.map +1 -0
  247. package/dist/precise.d.ts +8 -0
  248. package/dist/precise.d.ts.map +1 -0
  249. package/dist/precise.js +28 -0
  250. package/dist/precise.js.map +1 -0
  251. package/dist/processor.d.ts +20 -0
  252. package/dist/processor.d.ts.map +1 -0
  253. package/dist/processor.js +102 -0
  254. package/dist/processor.js.map +1 -0
  255. package/dist/request-api.d.ts +12 -0
  256. package/dist/request-api.d.ts.map +1 -0
  257. package/dist/request-api.js +31 -0
  258. package/dist/request-api.js.map +1 -0
  259. package/dist/request-attributes.d.ts +9 -0
  260. package/dist/request-attributes.d.ts.map +1 -0
  261. package/dist/request-attributes.js +48 -0
  262. package/dist/request-attributes.js.map +1 -0
  263. package/dist/request-capture.d.ts +32 -0
  264. package/dist/request-capture.d.ts.map +1 -0
  265. package/dist/request-capture.js +94 -0
  266. package/dist/request-capture.js.map +1 -0
  267. package/dist/route-timing.d.ts +6 -0
  268. package/dist/route-timing.d.ts.map +1 -0
  269. package/dist/route-timing.js +25 -0
  270. package/dist/route-timing.js.map +1 -0
  271. package/dist/sampling.d.ts +37 -0
  272. package/dist/sampling.d.ts.map +1 -0
  273. package/dist/sampling.js +120 -0
  274. package/dist/sampling.js.map +1 -0
  275. package/dist/spans.d.ts +9 -0
  276. package/dist/spans.d.ts.map +1 -0
  277. package/dist/spans.js +17 -0
  278. package/dist/spans.js.map +1 -0
  279. package/dist/store-types.d.ts +22 -0
  280. package/dist/store-types.d.ts.map +1 -0
  281. package/dist/store-types.js +2 -0
  282. package/dist/store-types.js.map +1 -0
  283. package/dist/store.d.ts +59 -0
  284. package/dist/store.d.ts.map +1 -0
  285. package/dist/store.js +194 -0
  286. package/dist/store.js.map +1 -0
  287. package/dist/tracing.d.ts +20 -0
  288. package/dist/tracing.d.ts.map +1 -0
  289. package/dist/tracing.js +45 -0
  290. package/dist/tracing.js.map +1 -0
  291. package/dist/types.d.ts +127 -0
  292. package/dist/types.d.ts.map +1 -0
  293. package/dist/types.js +2 -0
  294. package/dist/types.js.map +1 -0
  295. package/dist/ui.d.ts +6 -0
  296. package/dist/ui.d.ts.map +1 -0
  297. package/dist/ui.js +62 -0
  298. package/dist/ui.js.map +1 -0
  299. package/dist/wizelens.d.ts +5 -0
  300. package/dist/wizelens.d.ts.map +1 -0
  301. package/dist/wizelens.js +127 -0
  302. package/dist/wizelens.js.map +1 -0
  303. package/package.json +109 -3
@@ -0,0 +1,159 @@
1
+ import { untraced } from "./db.js";
2
+ import { mkdirSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import { dirname } from "node:path";
5
+ import { ATTR_BROWSER_SESSION } from "@wizeworks/lens-core";
6
+ import { prepareStatements, SCHEMA, SCHEMA_VERSION } from "./persist-schema.js";
7
+ import { hookProcessExit, parseArray } from "./persist-util.js";
8
+ const require = createRequire(import.meta.url);
9
+ /** Writes the store to a SQLite file and loads it back on startup; any error turns it off with one warning. */
10
+ export class SqlitePersister {
11
+ path;
12
+ #store;
13
+ #options;
14
+ #now;
15
+ #db;
16
+ #stmts;
17
+ #timer;
18
+ #failed = false;
19
+ #unhook;
20
+ constructor(store, options) {
21
+ this.#store = store;
22
+ this.#options = options;
23
+ this.path = options.path;
24
+ this.#now = options.now ?? Date.now;
25
+ }
26
+ get active() {
27
+ return this.#db !== undefined && !this.#failed;
28
+ }
29
+ /** Open the file, prune it, and load recent traces into the store. Returns false on failure. */
30
+ open() {
31
+ return untraced(() => this.#openFile());
32
+ }
33
+ #openFile() {
34
+ try {
35
+ // Loaded lazily so `storage: "memory"` never touches node:sqlite.
36
+ const { DatabaseSync } = require("node:sqlite");
37
+ mkdirSync(dirname(this.path), { recursive: true });
38
+ const db = new DatabaseSync(this.path);
39
+ this.#db = db;
40
+ db.exec("PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA busy_timeout = 2000;");
41
+ db.exec(SCHEMA);
42
+ const setMeta = db.prepare("INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value");
43
+ setMeta.run("schema", SCHEMA_VERSION);
44
+ setMeta.run("service", this.#options.serviceName);
45
+ this.#stmts = prepareStatements(db);
46
+ this.#prune();
47
+ this.#store.load(this.#loadRecent());
48
+ return true;
49
+ }
50
+ catch (err) {
51
+ this.#fail(err);
52
+ return false;
53
+ }
54
+ }
55
+ /** Flush every `intervalMs`, and once more when the process exits. */
56
+ start() {
57
+ if (!this.active || this.#timer)
58
+ return;
59
+ this.#timer = setInterval(() => this.flush(), this.#options.intervalMs ?? 500);
60
+ this.#timer.unref();
61
+ this.#unhook = hookProcessExit(() => this.flush());
62
+ }
63
+ /** Write all changed traces in one transaction, then prune. Synchronous on purpose (safe in `exit`). */
64
+ flush() {
65
+ untraced(() => this.#flushNow());
66
+ }
67
+ #flushNow() {
68
+ const db = this.#db;
69
+ const stmts = this.#stmts;
70
+ if (!db || !stmts || this.#failed)
71
+ return;
72
+ const changes = this.#store.drainChanges();
73
+ if (changes.length === 0)
74
+ return;
75
+ const now = this.#now();
76
+ try {
77
+ db.exec("BEGIN");
78
+ for (const c of changes) {
79
+ stmts.upsertTrace.run(c.traceId, c.startMs, now, JSON.stringify(c.remotes));
80
+ for (const s of c.spans) {
81
+ const session = s.attributes[ATTR_BROWSER_SESSION];
82
+ stmts.upsertSpan.run(s.traceId, s.spanId, s.parentSpanId, s.name, s.kind, s.category, s.service, s.startMs, s.durationMs, s.status, typeof session === "string" && session ? session : null, JSON.stringify(s));
83
+ }
84
+ for (const { seq, log } of c.logs)
85
+ stmts.insertLog.run(c.traceId, seq, log.timeMs, log.level, JSON.stringify(log));
86
+ }
87
+ this.#prune();
88
+ db.exec("COMMIT");
89
+ }
90
+ catch (err) {
91
+ try {
92
+ db.exec("ROLLBACK");
93
+ }
94
+ catch {
95
+ // already rolled back
96
+ }
97
+ this.#fail(err);
98
+ }
99
+ }
100
+ /** Final flush, then close the file. */
101
+ close() {
102
+ if (this.#timer)
103
+ clearInterval(this.#timer);
104
+ this.#timer = undefined;
105
+ this.#unhook?.();
106
+ this.#unhook = undefined;
107
+ this.flush();
108
+ try {
109
+ this.#db?.close();
110
+ }
111
+ catch {
112
+ // closing is best effort
113
+ }
114
+ this.#db = undefined;
115
+ }
116
+ #prune() {
117
+ const stmts = this.#stmts;
118
+ stmts.pruneAge.run(this.#now() - this.#store.maxAgeMs);
119
+ stmts.pruneCount.run(this.#store.maxTraces);
120
+ stmts.pruneSpans.run();
121
+ stmts.pruneLogs.run();
122
+ }
123
+ #loadRecent() {
124
+ const db = this.#db;
125
+ const rows = db
126
+ .prepare("SELECT trace_id, start_ms, remotes FROM traces ORDER BY start_ms DESC LIMIT ?")
127
+ .all(this.#store.maxTraces);
128
+ const spansOf = db.prepare("SELECT json FROM spans WHERE trace_id = ?");
129
+ const logsOf = db.prepare("SELECT json FROM logs WHERE trace_id = ? ORDER BY seq");
130
+ // Oldest first, so the ring buffer evicts in the right order.
131
+ return rows.reverse().map((r) => ({
132
+ traceId: r.trace_id,
133
+ startMs: r.start_ms,
134
+ remotes: parseArray(r.remotes),
135
+ spans: spansOf.all(r.trace_id).map((x) => JSON.parse(x.json)),
136
+ logs: logsOf.all(r.trace_id).map((x) => JSON.parse(x.json)),
137
+ }));
138
+ }
139
+ #fail(err) {
140
+ if (this.#failed)
141
+ return;
142
+ this.#failed = true;
143
+ if (this.#timer)
144
+ clearInterval(this.#timer);
145
+ this.#timer = undefined;
146
+ this.#unhook?.();
147
+ this.#unhook = undefined;
148
+ try {
149
+ this.#db?.close();
150
+ }
151
+ catch {
152
+ // ignore
153
+ }
154
+ this.#db = undefined;
155
+ const message = err instanceof Error ? err.message : String(err);
156
+ (this.#options.warn ?? console.warn)(`[wizelens] Could not use the trace file ${this.path} (${message}). Traces are kept in memory only.`);
157
+ }
158
+ }
159
+ //# sourceMappingURL=persist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persist.js","sourceRoot":"","sources":["../src/persist.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type Tracer, type TracerProvider } from "@opentelemetry/api";
2
+ /** Epoch ms with sub-ms precision. OTel anchors each span on Date.now(), which is whole ms only. */
3
+ export declare const preciseNow: () => number;
4
+ /** A tracer that gives every span an exact start and end, so sub-ms queries keep their order. */
5
+ export declare function preciseTracer(tracer: Tracer): Tracer;
6
+ /** The same, for instrumentations that ask a provider for their tracer. */
7
+ export declare function preciseProvider(provider: TracerProvider): TracerProvider;
8
+ //# sourceMappingURL=precise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"precise.d.ts","sourceRoot":"","sources":["../src/precise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE1I,oGAAoG;AACpG,eAAO,MAAM,UAAU,QAAO,MAAoD,CAAC;AAmBnF,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,GAAG,cAAc,CAExE"}
@@ -0,0 +1,28 @@
1
+ import { context } from "@opentelemetry/api";
2
+ /** Epoch ms with sub-ms precision. OTel anchors each span on Date.now(), which is whole ms only. */
3
+ export const preciseNow = () => performance.timeOrigin + performance.now();
4
+ function preciseSpan(span) {
5
+ const end = span.end.bind(span);
6
+ span.end = (time) => end(time ?? preciseNow());
7
+ return span;
8
+ }
9
+ /** startActiveSpan with an exact start and end. Next.js starts all its spans this way. */
10
+ function preciseActive(tracer) {
11
+ const start = tracer.startActiveSpan.bind(tracer);
12
+ return ((name, ...rest) => {
13
+ const fn = rest.pop();
14
+ const [options = {}, ctx = context.active()] = rest;
15
+ const timed = { ...options, startTime: options.startTime ?? preciseNow() };
16
+ return start(name, timed, ctx, (span) => fn(preciseSpan(span)));
17
+ });
18
+ }
19
+ /** A tracer that gives every span an exact start and end, so sub-ms queries keep their order. */
20
+ export function preciseTracer(tracer) {
21
+ const startSpan = (name, options = {}, ctx) => preciseSpan(tracer.startSpan(name, { ...options, startTime: options.startTime ?? preciseNow() }, ctx));
22
+ return { startSpan, startActiveSpan: preciseActive(tracer) };
23
+ }
24
+ /** The same, for instrumentations that ask a provider for their tracer. */
25
+ export function preciseProvider(provider) {
26
+ return { getTracer: (name, version, options) => preciseTracer(provider.getTracer(name, version, options)) };
27
+ }
28
+ //# sourceMappingURL=precise.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"precise.js","sourceRoot":"","sources":["../src/precise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,OAAO,EAAiF,MAAM,oBAAoB,CAAC;AAE1I,oGAAoG;AACpG,MAAM,CAAC,MAAM,UAAU,GAAG,GAAW,EAAE,CAAC,WAAW,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;AAEnF,SAAS,WAAW,CAAC,IAAU;IAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAgB,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,IAAI,UAAU,EAAE,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0FAA0F;AAC1F,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAgF,CAAC;IACjI,OAAO,CAAC,CAAC,IAAY,EAAE,GAAG,IAAe,EAAE,EAAE;QAC3C,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAA6B,CAAC;QACjD,MAAM,CAAC,OAAO,GAAG,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,IAAsD,CAAC;QACtG,MAAM,KAAK,GAAG,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,UAAU,EAAE,EAAE,CAAC;QAC3E,OAAO,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC,CAA8B,CAAC;AAClC,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,OAAO,GAAgB,EAAE,EAAE,GAAa,EAAQ,EAAE,CACjF,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,UAAU,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACzG,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,eAAe,CAAC,QAAwB;IACtD,OAAO,EAAE,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;AAC9G,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type Context } from "@opentelemetry/api";
2
+ import type { ReadableSpan, Span as SdkSpan, SpanProcessor } from "@opentelemetry/sdk-trace-base";
3
+ import { type Span } from "@wizeworks/lens-core";
4
+ import type { TraceStore } from "./store.js";
5
+ /** Set this attribute to force a contract category. Removed before storing. */
6
+ export declare const CATEGORY_ATTR = "wizelens.category";
7
+ /** Map a finished OTel span to a contract Span. */
8
+ export declare function toContractSpan(span: ReadableSpan, service: string, redactKeys: readonly string[]): Span;
9
+ /** SpanProcessor that writes every finished span into the in-memory store. */
10
+ export declare class StoreSpanProcessor implements SpanProcessor {
11
+ private readonly store;
12
+ private readonly service;
13
+ private readonly redactKeys;
14
+ constructor(store: TraceStore, service: string, redactKeys: readonly string[]);
15
+ onStart(_span: SdkSpan, _parentContext: Context): void;
16
+ onEnd(span: ReadableSpan): void;
17
+ forceFlush(): Promise<void>;
18
+ shutdown(): Promise<void>;
19
+ }
20
+ //# sourceMappingURL=processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processor.d.ts","sourceRoot":"","sources":["../src/processor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAA4B,MAAM,oBAAoB,CAAC;AAE5E,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,IAAI,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAClG,OAAO,EAEL,KAAK,IAAI,EAMV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,+EAA+E;AAC/E,eAAO,MAAM,aAAa,sBAAsB,CAAC;AA0CjD,mDAAmD;AACnD,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CA0BvG;AAED,8EAA8E;AAC9E,qBAAa,kBAAmB,YAAW,aAAa;IAEpD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAH7B,YACmB,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,SAAS,MAAM,EAAE,EAC5C;IAEJ,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,GAAG,IAAI,CAAG;IAEzD,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAI9B;IAED,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1B;IAED,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAExB;CACF"}
@@ -0,0 +1,102 @@
1
+ import { SpanKind, SpanStatusCode } from "@opentelemetry/api";
2
+ import { hrTimeToMilliseconds } from "@opentelemetry/core";
3
+ import { isDbCall, redactAttributes, toAttributeValue, } from "@wizeworks/lens-core";
4
+ /** Set this attribute to force a contract category. Removed before storing. */
5
+ export const CATEGORY_ATTR = "wizelens.category";
6
+ const KINDS = {
7
+ [SpanKind.INTERNAL]: "internal",
8
+ [SpanKind.SERVER]: "server",
9
+ [SpanKind.CLIENT]: "client",
10
+ [SpanKind.PRODUCER]: "producer",
11
+ [SpanKind.CONSUMER]: "consumer",
12
+ };
13
+ function toAttributes(attrs) {
14
+ const out = {};
15
+ for (const [k, v] of Object.entries(attrs))
16
+ out[k] = toAttributeValue(v);
17
+ return out;
18
+ }
19
+ function categoryOf(span, attrs) {
20
+ const forced = attrs[CATEGORY_ATTR];
21
+ if (typeof forced === "string")
22
+ return forced;
23
+ if (attrs["messaging.system"] != null)
24
+ return "messaging";
25
+ if (isDbCall(attrs))
26
+ return "db";
27
+ if (span.kind === SpanKind.SERVER && attrs["rpc.system"] != null)
28
+ return "http.server";
29
+ if (span.kind === SpanKind.CLIENT && attrs["rpc.system"] != null)
30
+ return "http.client";
31
+ if (span.kind === SpanKind.SERVER && attrs["http.request.method"] != null)
32
+ return "http.server";
33
+ if (span.kind === SpanKind.CLIENT && attrs["http.request.method"] != null)
34
+ return "http.client";
35
+ return "internal";
36
+ }
37
+ function clientName(attrs, fallback) {
38
+ const method = String(attrs["http.request.method"] ?? fallback);
39
+ const full = attrs["url.full"];
40
+ if (typeof full === "string") {
41
+ try {
42
+ const u = new URL(full);
43
+ return `${method} ${u.host}${u.pathname}`;
44
+ }
45
+ catch {
46
+ // keep fallback
47
+ }
48
+ }
49
+ return fallback;
50
+ }
51
+ /** Map a finished OTel span to a contract Span. */
52
+ export function toContractSpan(span, service, redactKeys) {
53
+ const ctx = span.spanContext();
54
+ const raw = toAttributes(span.attributes);
55
+ const category = categoryOf(span, raw);
56
+ delete raw[CATEGORY_ATTR];
57
+ const attributes = redactAttributes(raw, redactKeys);
58
+ const status = span.status.code === SpanStatusCode.ERROR ? "error" : span.status.code === SpanStatusCode.OK ? "ok" : "unset";
59
+ return {
60
+ traceId: ctx.traceId,
61
+ spanId: ctx.spanId,
62
+ parentSpanId: span.parentSpanContext?.spanId ?? null,
63
+ name: category === "http.client" ? clientName(attributes, span.name) : span.name,
64
+ kind: KINDS[span.kind] ?? "internal",
65
+ category,
66
+ service,
67
+ startMs: hrTimeToMilliseconds(span.startTime),
68
+ durationMs: hrTimeToMilliseconds(span.duration),
69
+ status,
70
+ statusMessage: span.status.message ?? null,
71
+ attributes,
72
+ events: span.events.map((e) => ({
73
+ name: e.name,
74
+ timeMs: hrTimeToMilliseconds(e.time),
75
+ attributes: redactAttributes(toAttributes(e.attributes ?? {}), redactKeys),
76
+ })),
77
+ };
78
+ }
79
+ /** SpanProcessor that writes every finished span into the in-memory store. */
80
+ export class StoreSpanProcessor {
81
+ store;
82
+ service;
83
+ redactKeys;
84
+ constructor(store, service, redactKeys) {
85
+ this.store = store;
86
+ this.service = service;
87
+ this.redactKeys = redactKeys;
88
+ }
89
+ onStart(_span, _parentContext) { }
90
+ onEnd(span) {
91
+ // A local root has no parent, or a parent in another process.
92
+ const parent = span.parentSpanContext;
93
+ this.store.addSpan(toContractSpan(span, this.service, this.redactKeys), !parent || !!parent.isRemote);
94
+ }
95
+ forceFlush() {
96
+ return Promise.resolve();
97
+ }
98
+ shutdown() {
99
+ return Promise.resolve();
100
+ }
101
+ }
102
+ //# sourceMappingURL=processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processor.js","sourceRoot":"","sources":["../src/processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { LogWriter } from "./logger.js";
3
+ import type { Next } from "./types.js";
4
+ /** Tag the running request. A tag without a value is stored as `true`. */
5
+ export declare function tag(key: string, value?: string): void;
6
+ /** Set `enduser.id` on the running request. */
7
+ export declare function setUser(id: string): void;
8
+ /** Record an exception on the innermost active span. */
9
+ export declare function recordException(err: unknown): void;
10
+ /** Express error middleware: records the error on the request span and as an error log. */
11
+ export declare function createErrorMiddleware(write: LogWriter, service: string): (err: unknown, req: IncomingMessage, _res: ServerResponse, next: Next) => void;
12
+ //# sourceMappingURL=request-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-api.d.ts","sourceRoot":"","sources":["../src/request-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,0EAA0E;AAC1E,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAGrD;AAED,+CAA+C;AAC/C,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAExC;AAED,wDAAwD;AACxD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAGlD;AAED,2FAA2F;AAC3F,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,SAChC,OAAO,OAAO,eAAe,QAAQ,cAAc,QAAQ,IAAI,KAAG,IAAI,CAM5G"}
@@ -0,0 +1,31 @@
1
+ import { TAG_PREFIX } from "@wizeworks/lens-core";
2
+ import { requestSpan } from "./capture.js";
3
+ import { activeSpan, currentServerSpan, recordOn } from "./spans.js";
4
+ /** Tag the running request. A tag without a value is stored as `true`. */
5
+ export function tag(key, value) {
6
+ const k = key.trim();
7
+ if (k)
8
+ currentServerSpan()?.setAttribute(`${TAG_PREFIX}${k}`, value ?? true);
9
+ }
10
+ /** Set `enduser.id` on the running request. */
11
+ export function setUser(id) {
12
+ if (id)
13
+ currentServerSpan()?.setAttribute("enduser.id", id);
14
+ }
15
+ /** Record an exception on the innermost active span. */
16
+ export function recordException(err) {
17
+ const span = activeSpan();
18
+ if (span)
19
+ recordOn(span, err);
20
+ }
21
+ /** Express error middleware: records the error on the request span and as an error log. */
22
+ export function createErrorMiddleware(write, service) {
23
+ return function errorMiddleware(err, req, _res, next) {
24
+ const span = requestSpan(req) ?? activeSpan();
25
+ if (span)
26
+ recordOn(span, err);
27
+ write("error", service, err instanceof Error ? err.message : String(err));
28
+ next(err);
29
+ };
30
+ }
31
+ //# sourceMappingURL=request-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-api.js","sourceRoot":"","sources":["../src/request-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGrE,0EAA0E;AAC1E,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,KAAc;IAC7C,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACrB,IAAI,CAAC;QAAE,iBAAiB,EAAE,EAAE,YAAY,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC;AAC/E,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,OAAO,CAAC,EAAU;IAChC,IAAI,EAAE;QAAE,iBAAiB,EAAE,EAAE,YAAY,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;IAC1B,IAAI,IAAI;QAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,qBAAqB,CAAC,KAAgB,EAAE,OAAe;IACrE,OAAO,SAAS,eAAe,CAAC,GAAY,EAAE,GAAoB,EAAE,IAAoB,EAAE,IAAU;QAClG,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;QAC9C,IAAI,IAAI;YAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC9B,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1E,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { IncomingHttpHeaders, IncomingMessage, OutgoingHttpHeaders } from "node:http";
2
+ import type { Attributes as OtelAttributes } from "@opentelemetry/api";
3
+ /** Headers as `{prefix}{lower-case name}` attributes. Redaction happens when the span is stored. */
4
+ export declare function headerAttributes(headers: IncomingHttpHeaders | OutgoingHttpHeaders, prefix: string): OtelAttributes;
5
+ /** First X-Forwarded-For address, else the socket peer. IPv4-mapped IPv6 is shown as IPv4. */
6
+ export declare function clientAddress(req: IncomingMessage): string | undefined;
7
+ /** Attributes known when the request starts. */
8
+ export declare function requestAttributes(req: IncomingMessage, method: string, path: string, rawUrl: string): OtelAttributes;
9
+ //# sourceMappingURL=request-attributes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-attributes.d.ts","sourceRoot":"","sources":["../src/request-attributes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAQvE,oGAAoG;AACpG,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,GAAG,mBAAmB,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAUnH;AAED,8FAA8F;AAC9F,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAGtE;AAED,gDAAgD;AAChD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAkBpH"}
@@ -0,0 +1,48 @@
1
+ import { REQUEST_HEADER_PREFIX } from "@wizeworks/lens-core";
2
+ import { firstHeader } from "./http-util.js";
3
+ import { CATEGORY_ATTR } from "./processor.js";
4
+ const MAX_HEADERS = 50;
5
+ const MAX_HEADER_VALUE = 1024;
6
+ /** Headers as `{prefix}{lower-case name}` attributes. Redaction happens when the span is stored. */
7
+ export function headerAttributes(headers, prefix) {
8
+ const out = {};
9
+ let count = 0;
10
+ for (const [name, value] of Object.entries(headers)) {
11
+ if (value === undefined || count >= MAX_HEADERS)
12
+ continue;
13
+ const text = Array.isArray(value) ? value.join(", ") : String(value);
14
+ out[`${prefix}${name.toLowerCase()}`] = text.slice(0, MAX_HEADER_VALUE);
15
+ count++;
16
+ }
17
+ return out;
18
+ }
19
+ /** First X-Forwarded-For address, else the socket peer. IPv4-mapped IPv6 is shown as IPv4. */
20
+ export function clientAddress(req) {
21
+ const raw = firstHeader(req.headers["x-forwarded-for"]) ?? req.socket?.remoteAddress;
22
+ return raw?.replace(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/, "$1");
23
+ }
24
+ /** Attributes known when the request starts. */
25
+ export function requestAttributes(req, method, path, rawUrl) {
26
+ const host = req.headers.host ?? "";
27
+ const attributes = {
28
+ [CATEGORY_ATTR]: "http.server",
29
+ "http.request.method": method,
30
+ "url.path": path,
31
+ "server.address": host.split(":")[0] ?? host,
32
+ ...headerAttributes(req.headers, REQUEST_HEADER_PREFIX),
33
+ };
34
+ const query = rawUrl.includes("?") ? rawUrl.slice(rawUrl.indexOf("?") + 1) : "";
35
+ if (query)
36
+ attributes["url.query"] = query;
37
+ const ua = req.headers["user-agent"];
38
+ if (ua)
39
+ attributes["user_agent.original"] = ua;
40
+ const client = clientAddress(req);
41
+ if (client)
42
+ attributes["client.address"] = client;
43
+ const size = Number(req.headers["content-length"]);
44
+ if (Number.isFinite(size) && size >= 0 && req.headers["content-length"] !== undefined)
45
+ attributes["http.request.body.size"] = size;
46
+ return attributes;
47
+ }
48
+ //# sourceMappingURL=request-attributes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-attributes.js","sourceRoot":"","sources":["../src/request-attributes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import { type Context, type Span as OtelSpan, type Tracer } from "@opentelemetry/api";
3
+ import type { W3CTraceContextPropagator } from "@opentelemetry/core";
4
+ export interface CaptureDeps {
5
+ tracer: Tracer;
6
+ basePath: string;
7
+ publicEndpoint: string | undefined;
8
+ selfEndpoints: Set<string>;
9
+ w3c: W3CTraceContextPropagator;
10
+ captureResponseBody: boolean;
11
+ handler: (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
12
+ }
13
+ /** One captured request: its server span and the context that makes it the parent of everything inside. */
14
+ export interface CapturedRequest {
15
+ span: OtelSpan;
16
+ ctx: Context;
17
+ startedAt: number;
18
+ }
19
+ /** The route template ("/orders/:id"), read when the response is done. Undefined when unknown. */
20
+ export type RouteOf = () => string | undefined;
21
+ /** Path of a raw url without the query. */
22
+ export declare const pathOf: (rawUrl: string) => string;
23
+ export declare const isOwnPath: (d: CaptureDeps, path: string) => boolean;
24
+ /** A CORS preflight. The browser sends it before a cross-origin call, with no traceparent, so it is not traced. */
25
+ export declare const isPreflight: (req: IncomingMessage) => boolean;
26
+ /** Serve the dashboard and API. Resolves when the response is written. */
27
+ export declare function serveOwnPath(d: CaptureDeps, req: IncomingMessage, res: ServerResponse): Promise<void>;
28
+ /** Start the server span of one request on the raw Node objects. Works for any framework that runs on node:http. */
29
+ export declare function captureRequest(d: CaptureDeps, req: IncomingMessage, res: ServerResponse, rawUrl: string, routeOf: RouteOf): CapturedRequest;
30
+ /** The server span WizeLens started for this request, if any. */
31
+ export declare function requestSpan(req: IncomingMessage): OtelSpan | undefined;
32
+ //# sourceMappingURL=request-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-capture.d.ts","sourceRoot":"","sources":["../src/request-capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,OAAO,EAAE,KAAK,OAAO,EAAyB,KAAK,IAAI,IAAI,QAAQ,EAAmC,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC9I,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAmBrE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,GAAG,EAAE,yBAAyB,CAAC;IAC/B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAED,2GAA2G;AAC3G,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,kGAAkG;AAClG,MAAM,MAAM,OAAO,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC;AAS/C,2CAA2C;AAC3C,eAAO,MAAM,MAAM,WAAY,MAAM,KAAG,MAAqC,CAAC;AAE9E,eAAO,MAAM,SAAS,MAAO,WAAW,QAAQ,MAAM,KAAG,OAAmE,CAAC;AAE7H,mHAAmH;AACnH,eAAO,MAAM,WAAW,QAAS,eAAe,KAAG,OAAiG,CAAC;AAErJ,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAQrG;AAkCD,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,eAAe,CAwB3I;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,QAAQ,GAAG,SAAS,CAEtE"}
@@ -0,0 +1,94 @@
1
+ import { context, ROOT_CONTEXT, SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
2
+ import { ATTR_REQUEST_ABORTED, ATTR_REQUEST_ID, ATTR_RESPONSE_BODY, ATTR_RESPONSE_BODY_TRUNCATED, HEADER_ENDPOINT, HEADER_TRACE, RESPONSE_HEADER_PREFIX, serverTimingValue, } from "@wizeworks/lens-core";
3
+ import { tapResponse } from "./body-capture.js";
4
+ import { keepExposeHeaders } from "./expose-headers.js";
5
+ import { firstHeader, sendJson } from "./http-util.js";
6
+ import { headerAttributes, requestAttributes } from "./request-attributes.js";
7
+ import { SERVER_SPAN } from "./spans.js";
8
+ const REQ_SPAN = Symbol.for("wizeworks.wizelens.span");
9
+ function endpointFor(req, d) {
10
+ if (d.publicEndpoint)
11
+ return d.publicEndpoint;
12
+ const proto = firstHeader(req.headers["x-forwarded-proto"]) ?? (req.socket.encrypted ? "https" : "http");
13
+ const host = firstHeader(req.headers["x-forwarded-host"]) ?? req.headers.host ?? "localhost";
14
+ return `${proto}://${host}${d.basePath}`;
15
+ }
16
+ /** Path of a raw url without the query. */
17
+ export const pathOf = (rawUrl) => rawUrl.split("?")[0] ?? "/";
18
+ export const isOwnPath = (d, path) => path === d.basePath || path.startsWith(d.basePath + "/");
19
+ /** A CORS preflight. The browser sends it before a cross-origin call, with no traceparent, so it is not traced. */
20
+ export const isPreflight = (req) => req.method === "OPTIONS" && req.headers["access-control-request-method"] !== undefined;
21
+ /** Serve the dashboard and API. Resolves when the response is written. */
22
+ export function serveOwnPath(d, req, res) {
23
+ return d.handler(req, res).then(() => undefined, (err) => {
24
+ if (!res.headersSent)
25
+ sendJson(res, 500, { error: String(err) });
26
+ else
27
+ res.end();
28
+ });
29
+ }
30
+ function finishSpan(span, res, tap, method, routeOf) {
31
+ // A close before the response finished: the client left, and no status was ever sent.
32
+ if (!res.writableFinished)
33
+ span.setAttribute(ATTR_REQUEST_ABORTED, true);
34
+ if (res.headersSent)
35
+ span.setAttribute("http.response.status_code", res.statusCode);
36
+ const route = routeOf();
37
+ if (route) {
38
+ span.setAttribute("http.route", route);
39
+ span.updateName(`${method} ${route}`);
40
+ }
41
+ span.setAttributes(headerAttributes(res.getHeaders(), RESPONSE_HEADER_PREFIX));
42
+ span.setAttribute("http.response.body.size", tap.bytes());
43
+ const body = tap.body();
44
+ if (body) {
45
+ span.setAttribute(ATTR_RESPONSE_BODY, body.text);
46
+ span.setAttribute(ATTR_RESPONSE_BODY_TRUNCATED, body.truncated);
47
+ }
48
+ if (res.statusCode >= 500)
49
+ span.setStatus({ code: SpanStatusCode.ERROR, message: `HTTP ${res.statusCode}` });
50
+ span.end();
51
+ }
52
+ function startSpan(d, req, rawUrl) {
53
+ const method = req.method ?? "GET";
54
+ const parentCtx = d.w3c.extract(ROOT_CONTEXT, req.headers, {
55
+ get: (carrier, key) => carrier[key],
56
+ keys: (carrier) => Object.keys(carrier),
57
+ });
58
+ const attributes = requestAttributes(req, method, pathOf(rawUrl), rawUrl);
59
+ const span = d.tracer.startSpan(`${method} ${pathOf(rawUrl)}`, { kind: SpanKind.SERVER, attributes }, parentCtx);
60
+ span.setAttribute(ATTR_REQUEST_ID, firstHeader(req.headers["x-request-id"]) ?? span.spanContext().spanId);
61
+ return { span, method, ctx: trace.setSpan(parentCtx, span).setValue(SERVER_SPAN, span) };
62
+ }
63
+ /** Start the server span of one request on the raw Node objects. Works for any framework that runs on node:http. */
64
+ export function captureRequest(d, req, res, rawUrl, routeOf) {
65
+ const startedAt = performance.now();
66
+ const { span, method, ctx } = startSpan(d, req, rawUrl);
67
+ const endpoint = endpointFor(req, d);
68
+ d.selfEndpoints.add(endpoint);
69
+ res.setHeader(HEADER_TRACE, span.spanContext().traceId);
70
+ res.setHeader(HEADER_ENDPOINT, endpoint);
71
+ // A page cannot read its own document headers, but it can read Server-Timing. The page load joins this trace with it.
72
+ res.appendHeader("Server-Timing", serverTimingValue(span.spanContext().traceId, endpoint));
73
+ keepExposeHeaders(res);
74
+ req[REQ_SPAN] = span;
75
+ const tap = tapResponse(res, d.captureResponseBody);
76
+ let ended = false;
77
+ const finish = () => {
78
+ if (ended)
79
+ return;
80
+ ended = true;
81
+ finishSpan(span, res, tap, method, routeOf);
82
+ };
83
+ res.once("finish", finish);
84
+ res.once("close", finish);
85
+ // Body and response events run in the request's context, so work in their listeners joins this trace.
86
+ context.bind(ctx, req);
87
+ context.bind(ctx, res);
88
+ return { span, ctx, startedAt };
89
+ }
90
+ /** The server span WizeLens started for this request, if any. */
91
+ export function requestSpan(req) {
92
+ return req[REQ_SPAN];
93
+ }
94
+ //# sourceMappingURL=request-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-capture.js","sourceRoot":"","sources":["../src/request-capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Span as OtelSpan } from "@opentelemetry/api";
2
+ /** Record `wizelens.server.routed_ms` when the router sets `target[property]`: the moment the matched route starts. */
3
+ export declare function watchRoute(target: object, property: string, span: OtelSpan, startedAt: number): void;
4
+ /** Record the routing time now. */
5
+ export declare function markRouted(span: OtelSpan, startedAt: number): void;
6
+ //# sourceMappingURL=route-timing.d.ts.map