autotel-devtools 23.0.0 → 23.1.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.
@@ -1,4 +1,4 @@
1
- const require_http = require('./http-Cqm_MAtc.cjs');
1
+ const require_http = require('./http-1afd_01N.cjs');
2
2
  let _grpc_grpc_js = require("@grpc/grpc-js");
3
3
 
4
4
  //#region src/server/grpc.ts
@@ -1,4 +1,4 @@
1
- import { c as decodeOtlpTraceRequest, o as decodeOtlpLogsRequest, s as decodeOtlpMetricsRequest } from "./http-Dbd9TIYU.js";
1
+ import { c as decodeOtlpTraceRequest, o as decodeOtlpLogsRequest, s as decodeOtlpMetricsRequest } from "./http-gk1xapnA.js";
2
2
  import { Server, ServerCredentials, status } from "@grpc/grpc-js";
3
3
 
4
4
  //#region src/server/grpc.ts
@@ -1528,6 +1528,42 @@ var DevtoolsStore = class {
1528
1528
  LIMIT ?`).all(Math.max(1, Math.min(limit, 500)));
1529
1529
  return [.../* @__PURE__ */ new Set([...Object.keys(schema.columns), ...rows.map((row) => row.key)])];
1530
1530
  }
1531
+ /**
1532
+ * Values of one attribute paired with another on the same entity.
1533
+ *
1534
+ * `searchAttributes` matches on value text, which cannot answer "what arms
1535
+ * does this experiment have". Pairing two keys across the same span can, and
1536
+ * that is what turns a pair of cohorts into something the viewer offers
1537
+ * rather than something the reader has to type.
1538
+ *
1539
+ * Rows arrive grouped by `key`, each group's values commonest first, so a
1540
+ * caller can build the groups in one pass and take the two commonest as a
1541
+ * default pair.
1542
+ *
1543
+ * The join runs over `attribute_occurrences`, not the `attribute_values`
1544
+ * dictionary: occurrences are deleted with their span, so retention prunes
1545
+ * them, and they carry the entity a value was seen on, so an arm is only
1546
+ * offered for the experiment it actually ran under. The dictionary can do
1547
+ * neither — it counts values for the lifetime of the database and forgets
1548
+ * which span each came from, which would offer arms belonging to a different
1549
+ * experiment and experiments whose spans are long gone.
1550
+ */
1551
+ pairedAttributeValues(signal, key, pairedKey, limit = 200) {
1552
+ return this.db.prepare(`
1553
+ SELECT a.value_json AS value_json, b.value_json AS paired_json, count(*) AS count
1554
+ FROM attribute_occurrences a
1555
+ JOIN attribute_occurrences b
1556
+ ON b.signal = a.signal AND b.entity_id = a.entity_id AND b.key = ?
1557
+ WHERE a.signal = ? AND a.key = ?
1558
+ GROUP BY a.value_json, b.value_json
1559
+ ORDER BY value_json ASC, count DESC, paired_json ASC
1560
+ LIMIT ?
1561
+ `).all(pairedKey, signal, key, Math.max(1, Math.min(limit, 500))).map((row) => ({
1562
+ value: JSON.parse(row.value_json),
1563
+ paired: JSON.parse(row.paired_json),
1564
+ count: Number(row.count)
1565
+ }));
1566
+ }
1531
1567
  searchAttributes(signal, value, limit = 50) {
1532
1568
  return this.db.prepare(`
1533
1569
  SELECT key, value_json, seen_count
@@ -2503,11 +2539,15 @@ var DevtoolsServer = class {
2503
2539
  this.log(`Client disconnected (${this.clients.size} total)`);
2504
2540
  });
2505
2541
  });
2506
- if (!options.server) this.httpServer.listen(this._port, () => {
2507
- const addr = this.httpServer.address();
2508
- if (addr && typeof addr === "object") this._port = addr.port;
2509
- this.log(`WebSocket server listening on port ${this._port}`);
2510
- });
2542
+ if (!options.server) {
2543
+ const listening = () => {
2544
+ const addr = this.httpServer.address();
2545
+ if (addr && typeof addr === "object") this._port = addr.port;
2546
+ this.log(`WebSocket server listening on port ${this._port}`);
2547
+ };
2548
+ if (options.host == null) this.httpServer.listen(this._port, listening);
2549
+ else this.httpServer.listen(this._port, options.host, listening);
2550
+ }
2511
2551
  }
2512
2552
  get port() {
2513
2553
  const addr = this.httpServer.address();
@@ -2721,6 +2761,9 @@ var DevtoolsServer = class {
2721
2761
  listQueryFields(signal) {
2722
2762
  return this.store.listQueryFields(signal);
2723
2763
  }
2764
+ pairedAttributeValues(signal, key, pairedKey, limit) {
2765
+ return this.store.pairedAttributeValues(signal, key, pairedKey, limit);
2766
+ }
2724
2767
  searchAttributes(signal, value, limit) {
2725
2768
  return this.store.searchAttributes(signal, value, limit);
2726
2769
  }
@@ -3435,6 +3478,12 @@ function attachDevtoolsRoutes(httpServer, devtools, options = {}) {
3435
3478
  }
3436
3479
  const params = new URL(url, "http://localhost").searchParams;
3437
3480
  const signal = params.get("signal") === "logs" ? "logs" : "traces";
3481
+ const key = params.get("key");
3482
+ const pair = params.get("pair");
3483
+ if (key !== null && pair !== null) {
3484
+ sendJson(res, 200, { pairs: devtools.pairedAttributeValues(signal, key, pair) });
3485
+ return;
3486
+ }
3438
3487
  sendJson(res, 200, { attributes: devtools.searchAttributes(signal, params.get("value") ?? "") });
3439
3488
  return;
3440
3489
  }
@@ -1499,6 +1499,42 @@ var DevtoolsStore = class {
1499
1499
  LIMIT ?`).all(Math.max(1, Math.min(limit, 500)));
1500
1500
  return [.../* @__PURE__ */ new Set([...Object.keys(schema.columns), ...rows.map((row) => row.key)])];
1501
1501
  }
1502
+ /**
1503
+ * Values of one attribute paired with another on the same entity.
1504
+ *
1505
+ * `searchAttributes` matches on value text, which cannot answer "what arms
1506
+ * does this experiment have". Pairing two keys across the same span can, and
1507
+ * that is what turns a pair of cohorts into something the viewer offers
1508
+ * rather than something the reader has to type.
1509
+ *
1510
+ * Rows arrive grouped by `key`, each group's values commonest first, so a
1511
+ * caller can build the groups in one pass and take the two commonest as a
1512
+ * default pair.
1513
+ *
1514
+ * The join runs over `attribute_occurrences`, not the `attribute_values`
1515
+ * dictionary: occurrences are deleted with their span, so retention prunes
1516
+ * them, and they carry the entity a value was seen on, so an arm is only
1517
+ * offered for the experiment it actually ran under. The dictionary can do
1518
+ * neither — it counts values for the lifetime of the database and forgets
1519
+ * which span each came from, which would offer arms belonging to a different
1520
+ * experiment and experiments whose spans are long gone.
1521
+ */
1522
+ pairedAttributeValues(signal, key, pairedKey, limit = 200) {
1523
+ return this.db.prepare(`
1524
+ SELECT a.value_json AS value_json, b.value_json AS paired_json, count(*) AS count
1525
+ FROM attribute_occurrences a
1526
+ JOIN attribute_occurrences b
1527
+ ON b.signal = a.signal AND b.entity_id = a.entity_id AND b.key = ?
1528
+ WHERE a.signal = ? AND a.key = ?
1529
+ GROUP BY a.value_json, b.value_json
1530
+ ORDER BY value_json ASC, count DESC, paired_json ASC
1531
+ LIMIT ?
1532
+ `).all(pairedKey, signal, key, Math.max(1, Math.min(limit, 500))).map((row) => ({
1533
+ value: JSON.parse(row.value_json),
1534
+ paired: JSON.parse(row.paired_json),
1535
+ count: Number(row.count)
1536
+ }));
1537
+ }
1502
1538
  searchAttributes(signal, value, limit = 50) {
1503
1539
  return this.db.prepare(`
1504
1540
  SELECT key, value_json, seen_count
@@ -2474,11 +2510,15 @@ var DevtoolsServer = class {
2474
2510
  this.log(`Client disconnected (${this.clients.size} total)`);
2475
2511
  });
2476
2512
  });
2477
- if (!options.server) this.httpServer.listen(this._port, () => {
2478
- const addr = this.httpServer.address();
2479
- if (addr && typeof addr === "object") this._port = addr.port;
2480
- this.log(`WebSocket server listening on port ${this._port}`);
2481
- });
2513
+ if (!options.server) {
2514
+ const listening = () => {
2515
+ const addr = this.httpServer.address();
2516
+ if (addr && typeof addr === "object") this._port = addr.port;
2517
+ this.log(`WebSocket server listening on port ${this._port}`);
2518
+ };
2519
+ if (options.host == null) this.httpServer.listen(this._port, listening);
2520
+ else this.httpServer.listen(this._port, options.host, listening);
2521
+ }
2482
2522
  }
2483
2523
  get port() {
2484
2524
  const addr = this.httpServer.address();
@@ -2692,6 +2732,9 @@ var DevtoolsServer = class {
2692
2732
  listQueryFields(signal) {
2693
2733
  return this.store.listQueryFields(signal);
2694
2734
  }
2735
+ pairedAttributeValues(signal, key, pairedKey, limit) {
2736
+ return this.store.pairedAttributeValues(signal, key, pairedKey, limit);
2737
+ }
2695
2738
  searchAttributes(signal, value, limit) {
2696
2739
  return this.store.searchAttributes(signal, value, limit);
2697
2740
  }
@@ -3406,6 +3449,12 @@ function attachDevtoolsRoutes(httpServer, devtools, options = {}) {
3406
3449
  }
3407
3450
  const params = new URL(url, "http://localhost").searchParams;
3408
3451
  const signal = params.get("signal") === "logs" ? "logs" : "traces";
3452
+ const key = params.get("key");
3453
+ const pair = params.get("pair");
3454
+ if (key !== null && pair !== null) {
3455
+ sendJson(res, 200, { pairs: devtools.pairedAttributeValues(signal, key, pair) });
3456
+ return;
3457
+ }
3409
3458
  sendJson(res, 200, { attributes: devtools.searchAttributes(signal, params.get("value") ?? "") });
3410
3459
  return;
3411
3460
  }
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_http = require('./http-Cqm_MAtc.cjs');
2
+ const require_http = require('./http-1afd_01N.cjs');
3
3
  const require_listen = require('./listen-l09RRHht.cjs');
4
4
  const require_server_exporter = require('./server/exporter.cjs');
5
5
  const require_server_log_exporter = require('./server/log-exporter.cjs');
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as SpanAttributes, t as AttributeValue } from "./types-DHDvZnnn.cjs";
2
2
  import { a as SpanData, i as LogData, n as ErrorGroup, o as TraceData, t as DevtoolsData } from "./types-B0tjwFqj.cjs";
3
- import { n as DevtoolsServer, t as DevtoolsSpanExporter } from "./exporter-C4uKgo7l.cjs";
3
+ import { n as DevtoolsServer, t as DevtoolsSpanExporter } from "./exporter-OoWkSMCR.cjs";
4
4
  import { DevtoolsLogExporter } from "./server/log-exporter.cjs";
5
5
  import { DevtoolsRemoteExporter } from "./server/remote-exporter.cjs";
6
6
  import { t as ErrorAggregator } from "./error-aggregator-DSwUvgFF.cjs";
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as SpanAttributes, t as AttributeValue } from "./types-DHDvZnnn.js";
2
2
  import { a as SpanData, i as LogData, n as ErrorGroup, o as TraceData, t as DevtoolsData } from "./types-DM8y4A9Z.js";
3
- import { n as DevtoolsServer, t as DevtoolsSpanExporter } from "./exporter-BrEcnzoT.js";
3
+ import { n as DevtoolsServer, t as DevtoolsSpanExporter } from "./exporter-C88W22vY.js";
4
4
  import { DevtoolsLogExporter } from "./server/log-exporter.js";
5
5
  import { DevtoolsRemoteExporter } from "./server/remote-exporter.js";
6
6
  import { t as ErrorAggregator } from "./error-aggregator-B52JI8jL.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ErrorAggregator, g as hostHeaderIsLoopback, l as DevtoolsServer, r as resolveSourceRoot, t as attachDevtoolsRoutes } from "./http-Dbd9TIYU.js";
1
+ import { C as ErrorAggregator, g as hostHeaderIsLoopback, l as DevtoolsServer, r as resolveSourceRoot, t as attachDevtoolsRoutes } from "./http-gk1xapnA.js";
2
2
  import { t as listenLoopbackDualStack } from "./listen-D-lLgfro.js";
3
3
  import { DevtoolsSpanExporter } from "./server/exporter.js";
4
4
  import { DevtoolsLogExporter } from "./server/log-exporter.js";
@@ -1,2 +1,2 @@
1
- import { t as DevtoolsSpanExporter } from "../exporter-C4uKgo7l.cjs";
1
+ import { t as DevtoolsSpanExporter } from "../exporter-OoWkSMCR.cjs";
2
2
  export { DevtoolsSpanExporter };
@@ -1,2 +1,2 @@
1
- import { t as DevtoolsSpanExporter } from "../exporter-BrEcnzoT.js";
1
+ import { t as DevtoolsSpanExporter } from "../exporter-C88W22vY.js";
2
2
  export { DevtoolsSpanExporter };
@@ -1,9 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_http = require('../http-Cqm_MAtc.cjs');
2
+ const require_http = require('../http-1afd_01N.cjs');
3
3
  const require_server_exporter = require('./exporter.cjs');
4
4
  const require_server_log_exporter = require('./log-exporter.cjs');
5
5
  const require_server_remote_exporter = require('./remote-exporter.cjs');
6
- const require_grpc = require('../grpc-CSWjMRiB.cjs');
6
+ const require_grpc = require('../grpc-D0B3P9sI.cjs');
7
7
 
8
8
  exports.DEVTOOLS_IDENTITY = require_http.DEVTOOLS_IDENTITY;
9
9
  exports.DevtoolsLogExporter = require_server_log_exporter.DevtoolsLogExporter;
@@ -1,6 +1,6 @@
1
1
  import "../types-DHDvZnnn.cjs";
2
2
  import { a as SpanData, i as LogData, n as ErrorGroup, o as TraceData, r as ErrorOccurrence, t as DevtoolsData } from "../types-B0tjwFqj.cjs";
3
- import { a as DevtoolsStoreOptions, c as QueryLogsArgs, d as QueryTracesArgs, f as QueryTracesResult, i as DevtoolsStore, l as QueryLogsResult, m as TimeWindow, n as DevtoolsServer, o as MetricCatalogEntry, p as SPAN_SCHEMA, r as DevtoolsServerOptions, s as MetricSeries, t as DevtoolsSpanExporter, u as QueryMetricSeriesArgs } from "../exporter-C4uKgo7l.cjs";
3
+ import { a as DevtoolsStoreOptions, c as QueryLogsArgs, d as QueryTracesArgs, f as QueryTracesResult, i as DevtoolsStore, l as QueryLogsResult, m as TimeWindow, n as DevtoolsServer, o as MetricCatalogEntry, p as SPAN_SCHEMA, r as DevtoolsServerOptions, s as MetricSeries, t as DevtoolsSpanExporter, u as QueryMetricSeriesArgs } from "../exporter-OoWkSMCR.cjs";
4
4
  import { DevtoolsLogExporter } from "./log-exporter.cjs";
5
5
  import { DevtoolsRemoteExporter, DevtoolsRemoteExporterOptions } from "./remote-exporter.cjs";
6
6
  import { t as ErrorAggregator } from "../error-aggregator-DSwUvgFF.cjs";
@@ -1,6 +1,6 @@
1
1
  import "../types-DHDvZnnn.js";
2
2
  import { a as SpanData, i as LogData, n as ErrorGroup, o as TraceData, r as ErrorOccurrence, t as DevtoolsData } from "../types-DM8y4A9Z.js";
3
- import { a as DevtoolsStoreOptions, c as QueryLogsArgs, d as QueryTracesArgs, f as QueryTracesResult, i as DevtoolsStore, l as QueryLogsResult, m as TimeWindow, n as DevtoolsServer, o as MetricCatalogEntry, p as SPAN_SCHEMA, r as DevtoolsServerOptions, s as MetricSeries, t as DevtoolsSpanExporter, u as QueryMetricSeriesArgs } from "../exporter-BrEcnzoT.js";
3
+ import { a as DevtoolsStoreOptions, c as QueryLogsArgs, d as QueryTracesArgs, f as QueryTracesResult, i as DevtoolsStore, l as QueryLogsResult, m as TimeWindow, n as DevtoolsServer, o as MetricCatalogEntry, p as SPAN_SCHEMA, r as DevtoolsServerOptions, s as MetricSeries, t as DevtoolsSpanExporter, u as QueryMetricSeriesArgs } from "../exporter-C88W22vY.js";
4
4
  import { DevtoolsLogExporter } from "./log-exporter.js";
5
5
  import { DevtoolsRemoteExporter, DevtoolsRemoteExporterOptions } from "./remote-exporter.js";
6
6
  import { t as ErrorAggregator } from "../error-aggregator-B52JI8jL.js";
@@ -1,7 +1,7 @@
1
- import { C as ErrorAggregator, S as resolveTelemetryLimits, _ as isLoopbackHostname, a as probePortHolder, b as appendWithLimit, c as decodeOtlpTraceRequest, d as parseOtlpLogs, f as parseOtlpTraces, g as hostHeaderIsLoopback, h as allowSensitiveRequest, i as DEVTOOLS_IDENTITY, l as DevtoolsServer, m as SPAN_SCHEMA, n as createDevtoolsHttpServer, o as decodeOtlpLogsRequest, p as DevtoolsStore, s as decodeOtlpMetricsRequest, t as attachDevtoolsRoutes, u as isProtobufContentType, v as originIsLoopback, x as applyTelemetryLimits, y as appendManyWithLimit } from "../http-Dbd9TIYU.js";
1
+ import { C as ErrorAggregator, S as resolveTelemetryLimits, _ as isLoopbackHostname, a as probePortHolder, b as appendWithLimit, c as decodeOtlpTraceRequest, d as parseOtlpLogs, f as parseOtlpTraces, g as hostHeaderIsLoopback, h as allowSensitiveRequest, i as DEVTOOLS_IDENTITY, l as DevtoolsServer, m as SPAN_SCHEMA, n as createDevtoolsHttpServer, o as decodeOtlpLogsRequest, p as DevtoolsStore, s as decodeOtlpMetricsRequest, t as attachDevtoolsRoutes, u as isProtobufContentType, v as originIsLoopback, x as applyTelemetryLimits, y as appendManyWithLimit } from "../http-gk1xapnA.js";
2
2
  import { DevtoolsSpanExporter } from "./exporter.js";
3
3
  import { DevtoolsLogExporter } from "./log-exporter.js";
4
4
  import { DevtoolsRemoteExporter } from "./remote-exporter.js";
5
- import { t as startOtlpGrpcReceiver } from "../grpc-CZEDUYCM.js";
5
+ import { t as startOtlpGrpcReceiver } from "../grpc-DY-C1jSU.js";
6
6
 
7
7
  export { DEVTOOLS_IDENTITY, DevtoolsLogExporter, DevtoolsRemoteExporter, DevtoolsServer, DevtoolsSpanExporter, DevtoolsStore, ErrorAggregator, SPAN_SCHEMA, allowSensitiveRequest, appendManyWithLimit, appendWithLimit, applyTelemetryLimits, attachDevtoolsRoutes, createDevtoolsHttpServer, decodeOtlpLogsRequest, decodeOtlpMetricsRequest, decodeOtlpTraceRequest, hostHeaderIsLoopback, isLoopbackHostname, isProtobufContentType, originIsLoopback, parseOtlpLogs, parseOtlpTraces, probePortHolder, resolveTelemetryLimits, startOtlpGrpcReceiver };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel-devtools",
3
- "version": "23.0.0",
3
+ "version": "23.1.0",
4
4
  "description": "Standalone OTLP receiver with web UI for local development",
5
5
  "type": "module",
6
6
  "sideEffects": false,