autotel-devtools 5.1.0 → 6.0.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.
@@ -21,6 +21,15 @@ interface SpanData {
21
21
  timestamp: number;
22
22
  attributes?: Record<string, any>;
23
23
  }>;
24
+ links?: Array<{
25
+ traceId: string;
26
+ spanId: string;
27
+ attributes?: Record<string, any>;
28
+ }>;
29
+ scope?: {
30
+ name?: string;
31
+ version?: string;
32
+ };
24
33
  }
25
34
  interface TraceData {
26
35
  traceId: string;
@@ -95,6 +104,12 @@ interface DevtoolsServerOptions {
95
104
  maxTraceCount?: number;
96
105
  maxLogCount?: number;
97
106
  maxMetricCount?: number;
107
+ /**
108
+ * Called after each ingest, with the incremental data just broadcast to WS
109
+ * clients. Lets an embedder (e.g. the VS Code extension) react to new
110
+ * telemetry — refresh its own tree views — while the server owns the buffer.
111
+ */
112
+ onData?: (incremental: DevtoolsData) => void;
98
113
  }
99
114
  declare class DevtoolsServer {
100
115
  private wss;
@@ -107,6 +122,7 @@ declare class DevtoolsServer {
107
122
  private limits;
108
123
  private verbose;
109
124
  private _port;
125
+ private onData?;
110
126
  constructor(options?: DevtoolsServerOptions);
111
127
  get port(): number;
112
128
  get clientCount(): number;
@@ -150,6 +166,7 @@ declare class DevtoolsSpanExporter implements SpanExporter {
150
166
  * Convert OpenTelemetry span to SpanData
151
167
  */
152
168
  private convertSpan;
169
+ private convertScope;
153
170
  /**
154
171
  * Convert OpenTelemetry SpanKind to string
155
172
  */
@@ -20,6 +20,15 @@ interface SpanData {
20
20
  timestamp: number;
21
21
  attributes?: Record<string, any>;
22
22
  }>;
23
+ links?: Array<{
24
+ traceId: string;
25
+ spanId: string;
26
+ attributes?: Record<string, any>;
27
+ }>;
28
+ scope?: {
29
+ name?: string;
30
+ version?: string;
31
+ };
23
32
  }
24
33
 
25
34
  declare function isGenAiSpan(span: SpanData): boolean;
@@ -20,6 +20,15 @@ interface SpanData {
20
20
  timestamp: number;
21
21
  attributes?: Record<string, any>;
22
22
  }>;
23
+ links?: Array<{
24
+ traceId: string;
25
+ spanId: string;
26
+ attributes?: Record<string, any>;
27
+ }>;
28
+ scope?: {
29
+ name?: string;
30
+ version?: string;
31
+ };
23
32
  }
24
33
 
25
34
  declare function isGenAiSpan(span: SpanData): boolean;
package/dist/index.cjs CHANGED
@@ -367,10 +367,12 @@ var DevtoolsServer = class {
367
367
  limits;
368
368
  verbose;
369
369
  _port;
370
+ onData;
370
371
  constructor(options = {}) {
371
372
  this.limits = resolveTelemetryLimits(options);
372
373
  this.verbose = options.verbose ?? false;
373
374
  this._port = options.port ?? 4318;
375
+ this.onData = options.onData;
374
376
  this.httpServer = options.server ?? http.createServer();
375
377
  this.wss = new ws.WebSocketServer({ server: this.httpServer, path: options.path ?? "/ws" });
376
378
  this.wss.on("connection", (ws) => {
@@ -464,6 +466,12 @@ var DevtoolsServer = class {
464
466
  client.send(msg);
465
467
  }
466
468
  }
469
+ if (this.onData) {
470
+ try {
471
+ this.onData(data);
472
+ } catch {
473
+ }
474
+ }
467
475
  }
468
476
  log(message) {
469
477
  if (this.verbose) console.log(`[autotel-devtools] ${message}`);
@@ -517,7 +525,10 @@ function flattenAttributes(attrs) {
517
525
  }
518
526
  function nanoToMs(nano) {
519
527
  if (!nano) return 0;
520
- return Number(BigInt(nano) / 1000000n);
528
+ const ns = BigInt(nano);
529
+ const ms = ns / 1000000n;
530
+ const remNs = ns % 1000000n;
531
+ return Number(ms) + Number(remNs) / 1e6;
521
532
  }
522
533
  var SPAN_KIND_MAP = {
523
534
  0: "INTERNAL",
@@ -555,6 +566,7 @@ function parseOtlpTraces(payload) {
555
566
  const service = String(resourceAttrs["service.name"] || "unknown");
556
567
  const scopeSpans = rs.scopeSpans || [];
557
568
  for (const ss of scopeSpans) {
569
+ const scope = ss.scope?.name ? { name: ss.scope.name, version: ss.scope.version || void 0 } : void 0;
558
570
  for (const span of ss.spans || []) {
559
571
  const traceId = normalizeHexId(span.traceId);
560
572
  if (!traceId) continue;
@@ -579,7 +591,13 @@ function parseOtlpTraces(payload) {
579
591
  name: e.name || "",
580
592
  timestamp: nanoToMs(e.timeUnixNano),
581
593
  attributes: flattenAttributes(e.attributes)
582
- }))
594
+ })),
595
+ links: (span.links || []).map((l) => ({
596
+ traceId: normalizeHexId(l.traceId),
597
+ spanId: normalizeHexId(l.spanId),
598
+ attributes: flattenAttributes(l.attributes)
599
+ })),
600
+ scope
583
601
  };
584
602
  const existing = traceMap.get(traceId);
585
603
  if (existing) {
@@ -1171,6 +1189,11 @@ var DevtoolsSpanExporter = class {
1171
1189
  timestamp: event.time[0] * 1e3 + event.time[1] / 1e6,
1172
1190
  attributes: event.attributes ? Object.fromEntries(Object.entries(event.attributes)) : void 0
1173
1191
  }));
1192
+ const links = span.links.map((link) => ({
1193
+ traceId: link.context.traceId,
1194
+ spanId: link.context.spanId,
1195
+ attributes: link.attributes ? Object.fromEntries(Object.entries(link.attributes)) : void 0
1196
+ }));
1174
1197
  return {
1175
1198
  traceId: spanContext.traceId,
1176
1199
  spanId: spanContext.spanId,
@@ -1185,9 +1208,15 @@ var DevtoolsSpanExporter = class {
1185
1208
  code: status,
1186
1209
  message: span.status.message
1187
1210
  },
1188
- events: events.length > 0 ? events : void 0
1211
+ events: events.length > 0 ? events : void 0,
1212
+ links: links.length > 0 ? links : void 0,
1213
+ scope: this.convertScope(span)
1189
1214
  };
1190
1215
  }
1216
+ convertScope(span) {
1217
+ const s = span.instrumentationScope ?? span.instrumentationLibrary;
1218
+ return s?.name ? { name: s.name, version: s.version || void 0 } : void 0;
1219
+ }
1191
1220
  /**
1192
1221
  * Convert OpenTelemetry SpanKind to string
1193
1222
  */