@neat.is/core 0.9.3 → 0.9.4

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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  routeSpanToProject,
3
3
  startDaemon
4
- } from "./chunk-2D4Y5QHE.js";
4
+ } from "./chunk-TGCWMMF6.js";
5
5
  import {
6
6
  ProjectNameCollisionError,
7
7
  addProject,
@@ -37,7 +37,7 @@ import {
37
37
  thresholdForEdgeType,
38
38
  touchLastSeen,
39
39
  writeAtomically
40
- } from "./chunk-EDE4XP2M.js";
40
+ } from "./chunk-IVVF37OU.js";
41
41
  import {
42
42
  startOtelGrpcReceiver
43
43
  } from "./chunk-ERE47MCR.js";
package/dist/neatd.cjs CHANGED
@@ -5419,6 +5419,64 @@ function latencyPercentiles(hist) {
5419
5419
  return { p50: round(quantile(hist, 0.5)), p95: round(quantile(hist, 0.95)) };
5420
5420
  }
5421
5421
 
5422
+ // src/stacktrace.ts
5423
+ init_cjs_shims();
5424
+ var FRAME_SHAPES = [
5425
+ // `File "<path>", line <N>, in <func>` — the "most recent call last" shape.
5426
+ { re: /File "([^"]+)", line (\d+)(?:, in (\S+))?/, file: 1, line: 2, fn: 3, deepest: "last" },
5427
+ // `at <func> (<path>:<line>:<col>)` — named call frame, most recent first.
5428
+ { re: /\bat\s+(.+?)\s+\((.+?):(\d+):\d+\)/, file: 2, line: 3, fn: 1, deepest: "first" },
5429
+ // `at <path>:<line>:<col>` — anonymous call frame, most recent first.
5430
+ { re: /\bat\s+(.+?):(\d+):\d+/, file: 1, line: 2, deepest: "first" },
5431
+ // `at <qualified.method>(<File.ext>:<line>)` — JVM-style, most recent first.
5432
+ { re: /\bat\s+(.+?)\((\S+\.\w+):(\d+)\)/, file: 2, line: 3, fn: 1, deepest: "first" }
5433
+ ];
5434
+ var VENDOR_MARKERS = [
5435
+ "node_modules",
5436
+ // dependency root
5437
+ "site-packages",
5438
+ // installed-package root
5439
+ "dist-packages",
5440
+ // distro-packaged root
5441
+ "node:"
5442
+ // runtime-internal module scheme (a stdlib/runtime-root frame)
5443
+ ];
5444
+ function matchFrame(line) {
5445
+ for (const shape of FRAME_SHAPES) {
5446
+ const m = shape.re.exec(line);
5447
+ if (!m) continue;
5448
+ const file = m[shape.file];
5449
+ const lineNo = Number(m[shape.line]);
5450
+ if (!file || !Number.isFinite(lineNo)) continue;
5451
+ const fn = shape.fn !== void 0 ? m[shape.fn] : void 0;
5452
+ return { frame: { file, line: lineNo, ...fn ? { fn } : {} }, deepest: shape.deepest };
5453
+ }
5454
+ return null;
5455
+ }
5456
+ function isApplicationFrame(file) {
5457
+ if (file.startsWith("<")) return false;
5458
+ const norm = file.split("\\").join("/");
5459
+ for (const marker of VENDOR_MARKERS) {
5460
+ if (norm.includes(marker)) return false;
5461
+ }
5462
+ return true;
5463
+ }
5464
+ function deepestApplicationFrame(stacktrace) {
5465
+ if (!stacktrace) return null;
5466
+ const appFrames = [];
5467
+ for (const raw of stacktrace.split("\n")) {
5468
+ const matched = matchFrame(raw);
5469
+ if (!matched) continue;
5470
+ if (!isApplicationFrame(matched.frame.file)) continue;
5471
+ appFrames.push(matched);
5472
+ }
5473
+ if (appFrames.length === 0) return null;
5474
+ const orientation = appFrames.some((f) => f.deepest === "last") ? "last" : "first";
5475
+ const oriented = appFrames.filter((f) => f.deepest === orientation);
5476
+ const chosen = orientation === "last" ? oriented[oriented.length - 1] : oriented[0];
5477
+ return chosen ? chosen.frame : null;
5478
+ }
5479
+
5422
5480
  // src/ingest.ts
5423
5481
  var HOUR_MS = 60 * 60 * 1e3;
5424
5482
  var DAY_MS = 24 * HOUR_MS;
@@ -6270,29 +6328,71 @@ async function appendConnectorIncident(errorsPath, input) {
6270
6328
  await import_node_fs7.promises.mkdir(import_node_path8.default.dirname(errorsPath), { recursive: true });
6271
6329
  await import_node_fs7.promises.appendFile(errorsPath, JSON.stringify(ev) + "\n", "utf8");
6272
6330
  }
6273
- function incidentAffectedNode(span, graph, scanPath) {
6331
+ function landIncidentCallSite(span, callSite, trusted, graph) {
6332
+ const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
6333
+ const canonicalService = serviceNodeName(graph, span) ?? span.service;
6334
+ const recovered = !trusted;
6335
+ if (graph) {
6336
+ const fusedFileId = (0, import_types8.fileId)(canonicalService, relPath);
6337
+ if (graph.hasNode(fusedFileId)) {
6338
+ const node = landObservedSymbol(
6339
+ graph,
6340
+ fusedFileId,
6341
+ canonicalService,
6342
+ relPath,
6343
+ { ...callSite, relPath },
6344
+ false
6345
+ );
6346
+ return {
6347
+ affectedNode: node,
6348
+ ...recovered ? {
6349
+ codeFilepath: relPath,
6350
+ ...callSite.line !== void 0 ? { codeLineno: callSite.line } : {}
6351
+ } : {}
6352
+ };
6353
+ }
6354
+ if (recovered) return null;
6355
+ }
6356
+ return { affectedNode: (0, import_types8.fileId)(span.service, relPath) };
6357
+ }
6358
+ function serviceNodeName(graph, span) {
6359
+ if (!graph) return void 0;
6360
+ const sid = resolveFusedServiceId(graph, span.service, span.env);
6361
+ if (!graph.hasNode(sid)) return void 0;
6362
+ const node = graph.getNodeAttributes(sid);
6363
+ return typeof node.name === "string" ? node.name : void 0;
6364
+ }
6365
+ function stacktraceCallSite(span, serviceNode, scanPath) {
6366
+ const frame = deepestApplicationFrame(span.exception?.stacktrace);
6367
+ if (!frame) return null;
6368
+ const relPath = relPathForRuntimeFile(frame.file, serviceNode, scanPath);
6369
+ if (!relPath) return null;
6370
+ return { relPath, line: frame.line, ...frame.fn ? { fn: frame.fn } : {} };
6371
+ }
6372
+ function incidentLocus(span, graph, scanPath) {
6274
6373
  const sid = graph ? resolveFusedServiceId(graph, span.service, span.env) : (0, import_types8.serviceId)(span.service, span.env);
6275
6374
  const serviceNode = graph && graph.hasNode(sid) ? graph.getNodeAttributes(sid) : void 0;
6276
6375
  const callSite = callSiteFromSpan(span, serviceNode, scanPath);
6277
6376
  if (callSite) {
6278
- const relPath = graph ? reconcileObservedRelPath(graph, span.service, callSite.relPath) : callSite.relPath;
6279
- const canonicalService = serviceNode && typeof serviceNode.name === "string" ? serviceNode.name : span.service;
6280
- if (graph) {
6281
- const fusedFileId = (0, import_types8.fileId)(canonicalService, relPath);
6282
- if (graph.hasNode(fusedFileId)) {
6283
- return landObservedSymbol(
6284
- graph,
6285
- fusedFileId,
6286
- canonicalService,
6287
- relPath,
6288
- { ...callSite, relPath },
6289
- false
6290
- );
6291
- }
6377
+ const landed = landIncidentCallSite(span, callSite, true, graph);
6378
+ if (landed) return landed;
6379
+ } else {
6380
+ const recovered = stacktraceCallSite(span, serviceNode, scanPath);
6381
+ if (recovered) {
6382
+ const landed = landIncidentCallSite(span, recovered, false, graph);
6383
+ if (landed) return landed;
6292
6384
  }
6293
- return (0, import_types8.fileId)(span.service, relPath);
6294
6385
  }
6295
- return sid;
6386
+ return { affectedNode: sid };
6387
+ }
6388
+ function incidentAffectedNode(span, graph, scanPath) {
6389
+ return incidentLocus(span, graph, scanPath).affectedNode;
6390
+ }
6391
+ function withRecoveredCodeAttrs(attrs, locus) {
6392
+ if (locus.codeFilepath === void 0) return attrs;
6393
+ attrs[CODE_FILEPATH_ATTR] = locus.codeFilepath;
6394
+ if (locus.codeLineno !== void 0) attrs[CODE_LINENO_ATTR] = locus.codeLineno;
6395
+ return attrs;
6296
6396
  }
6297
6397
  function sanitizeAttributes(attrs) {
6298
6398
  const out = {};
@@ -6305,7 +6405,8 @@ function sanitizeAttributes(attrs) {
6305
6405
  function buildErrorEventForReceiver(span, graph, scanPath) {
6306
6406
  if (span.statusCode !== 2) return null;
6307
6407
  const ts = span.startTimeIso ?? (/* @__PURE__ */ new Date()).toISOString();
6308
- const attrs = sanitizeAttributes(span.attributes);
6408
+ const locus = incidentLocus(span, graph, scanPath);
6409
+ const attrs = withRecoveredCodeAttrs(sanitizeAttributes(span.attributes), locus);
6309
6410
  return {
6310
6411
  id: `${span.traceId}:${span.spanId}`,
6311
6412
  timestamp: ts,
@@ -6316,7 +6417,7 @@ function buildErrorEventForReceiver(span, graph, scanPath) {
6316
6417
  ...span.exception?.type ? { exceptionType: span.exception.type } : {},
6317
6418
  ...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
6318
6419
  ...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
6319
- affectedNode: incidentAffectedNode(span, graph, scanPath)
6420
+ affectedNode: locus.affectedNode
6320
6421
  };
6321
6422
  }
6322
6423
  function makeErrorSpanWriter(errorsPath, graph, scanPath) {
@@ -6350,7 +6451,8 @@ async function recordFailingResponseIncident(ctx, span, affectedNode, timestamp,
6350
6451
  await appendErrorEvent(ctx, ev);
6351
6452
  }
6352
6453
  async function recordExceptionIncident(ctx, span, ts) {
6353
- const attrs = sanitizeAttributes(span.attributes);
6454
+ const locus = incidentLocus(span, ctx.graph, ctx.scanPath);
6455
+ const attrs = withRecoveredCodeAttrs(sanitizeAttributes(span.attributes), locus);
6354
6456
  const ev = {
6355
6457
  id: `${span.traceId}:${span.spanId}`,
6356
6458
  timestamp: ts,
@@ -6361,7 +6463,7 @@ async function recordExceptionIncident(ctx, span, ts) {
6361
6463
  ...span.exception?.type ? { exceptionType: span.exception.type } : {},
6362
6464
  ...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
6363
6465
  ...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
6364
- affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath)
6466
+ affectedNode: locus.affectedNode
6365
6467
  };
6366
6468
  await appendErrorEvent(ctx, ev);
6367
6469
  }
@@ -6664,7 +6766,8 @@ async function handleSpan(ctx, span) {
6664
6766
  if (span.statusCode === 2) {
6665
6767
  stitchTrace(ctx.graph, sourceId, ts);
6666
6768
  if (ctx.writeErrorEventInline !== false) {
6667
- const attrs = sanitizeAttributes(span.attributes);
6769
+ const locus = incidentLocus(span, ctx.graph, ctx.scanPath);
6770
+ const attrs = withRecoveredCodeAttrs(sanitizeAttributes(span.attributes), locus);
6668
6771
  const ev = {
6669
6772
  id: `${span.traceId}:${span.spanId}`,
6670
6773
  timestamp: ts,
@@ -6676,10 +6779,11 @@ async function handleSpan(ctx, span) {
6676
6779
  ...span.exception?.stacktrace ? { exceptionStacktrace: span.exception.stacktrace } : {},
6677
6780
  ...Object.keys(attrs).length > 0 ? { attributes: attrs } : {},
6678
6781
  // Attribute to where the failure originated — the symbol / file / service
6679
- // the throwing span named (incidentAffectedNode, ADR-191) the same
6680
- // source-based attribution the durable receiver write uses, not the
6681
- // outbound edge target this span happened to mint.
6682
- affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath)
6782
+ // the throwing span named (incidentAffectedNode / ADR-191, extended to
6783
+ // recover the locus from the stacktrace when the span stamped no code.*
6784
+ // attrs, ADR-216) the same source-based attribution the durable
6785
+ // receiver write uses, not the outbound edge target this span minted.
6786
+ affectedNode: locus.affectedNode
6683
6787
  };
6684
6788
  await appendErrorEvent(ctx, ev);
6685
6789
  }