inspeffct 1.0.5 → 1.0.7
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/bin.js +143 -170
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import * as NodeRuntime from '@effect/platform-node/NodeRuntime';
|
|
3
3
|
import * as NodeServices from '@effect/platform-node/NodeServices';
|
|
4
4
|
import * as Effect10 from 'effect/Effect';
|
|
5
|
-
import * as
|
|
5
|
+
import * as Command5 from 'effect/unstable/cli/Command';
|
|
6
6
|
import * as Argument3 from 'effect/unstable/cli/Argument';
|
|
7
7
|
import * as Context4 from 'effect/Context';
|
|
8
8
|
import * as Fiber from 'effect/Fiber';
|
|
@@ -30,14 +30,14 @@ import * as SchemaGetter from 'effect/SchemaGetter';
|
|
|
30
30
|
import { flow } from 'effect/Function';
|
|
31
31
|
import * as NodeFileSystem from '@effect/platform-node/NodeFileSystem';
|
|
32
32
|
import * as NodePath from '@effect/platform-node/NodePath';
|
|
33
|
-
import * as
|
|
33
|
+
import * as Flag from 'effect/unstable/cli/Flag';
|
|
34
34
|
import * as NodeSocketServer from '@effect/platform-node/NodeSocketServer';
|
|
35
35
|
import * as crypto from 'crypto';
|
|
36
36
|
import * as fs from 'fs';
|
|
37
37
|
import * as os from 'os';
|
|
38
38
|
import * as path from 'path';
|
|
39
39
|
import * as Console2 from 'effect/Console';
|
|
40
|
-
import * as
|
|
40
|
+
import * as Option4 from 'effect/Option';
|
|
41
41
|
import * as ChildProcess from 'effect/unstable/process/ChildProcess';
|
|
42
42
|
import * as Duration from 'effect/Duration';
|
|
43
43
|
import * as Graph from 'effect/Graph';
|
|
@@ -1110,18 +1110,18 @@ Effect10.map(IpcServer, (server) => server.messages);
|
|
|
1110
1110
|
Effect10.flatMap(IpcServer, (server) => server.subscribe);
|
|
1111
1111
|
|
|
1112
1112
|
// src/cli/options.ts
|
|
1113
|
-
var dataOption =
|
|
1114
|
-
|
|
1115
|
-
|
|
1113
|
+
var dataOption = Flag.string("data").pipe(
|
|
1114
|
+
Flag.withDescription("Path to SQLite database file"),
|
|
1115
|
+
Flag.withDefault(".inspeffct.db")
|
|
1116
1116
|
);
|
|
1117
|
-
var jsonOption =
|
|
1118
|
-
|
|
1119
|
-
|
|
1117
|
+
var jsonOption = Flag.boolean("json").pipe(
|
|
1118
|
+
Flag.withDescription("Output as JSON"),
|
|
1119
|
+
Flag.withDefault(false)
|
|
1120
1120
|
);
|
|
1121
|
-
var limitOption =
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1121
|
+
var limitOption = Flag.integer("limit").pipe(
|
|
1122
|
+
Flag.withAlias("n"),
|
|
1123
|
+
Flag.withDescription("Maximum number of results"),
|
|
1124
|
+
Flag.optional
|
|
1125
1125
|
);
|
|
1126
1126
|
var buildEnv = (bootloaderPath, ipcPath) => {
|
|
1127
1127
|
const requireFlag = `--require "${bootloaderPath}"`;
|
|
@@ -1163,7 +1163,7 @@ var makeServicesLayer = (dataPath) => {
|
|
|
1163
1163
|
var makeReadOnlyLayer = (dataPath) => layer5({ filename: dataPath });
|
|
1164
1164
|
|
|
1165
1165
|
// src/cli/connect.ts
|
|
1166
|
-
var command =
|
|
1166
|
+
var command = Command5.make(
|
|
1167
1167
|
"connect",
|
|
1168
1168
|
{
|
|
1169
1169
|
data: dataOption,
|
|
@@ -1182,7 +1182,19 @@ var command = Command6.make(
|
|
|
1182
1182
|
Effect10.scoped,
|
|
1183
1183
|
Effect10.provide(makeServicesLayer(data))
|
|
1184
1184
|
)
|
|
1185
|
-
).pipe(
|
|
1185
|
+
).pipe(
|
|
1186
|
+
Command5.withDescription("Connect to an existing CDP inspector endpoint"),
|
|
1187
|
+
Command5.withExamples([
|
|
1188
|
+
{
|
|
1189
|
+
command: "inspeffct connect ws://127.0.0.1:9229/<id>",
|
|
1190
|
+
description: "Connect to a running Node.js inspector endpoint"
|
|
1191
|
+
},
|
|
1192
|
+
{
|
|
1193
|
+
command: "inspeffct connect --data .inspeffct.db ws://127.0.0.1:9229/<id>",
|
|
1194
|
+
description: "Persist captured data to a specific SQLite database"
|
|
1195
|
+
}
|
|
1196
|
+
])
|
|
1197
|
+
);
|
|
1186
1198
|
var NODE_INSPECTOR_REGEX = /Debugger listening on (ws:\/\/[^\s]+)/;
|
|
1187
1199
|
var BUN_INSPECTOR_REGEX = /https:\/\/debug\.bun\.sh\/#([^\s]+)/;
|
|
1188
1200
|
var parseInspectorUrl = (chunk, decoder) => {
|
|
@@ -1197,13 +1209,13 @@ var parseInspectorUrl = (chunk, decoder) => {
|
|
|
1197
1209
|
}
|
|
1198
1210
|
return void 0;
|
|
1199
1211
|
};
|
|
1200
|
-
var command2 =
|
|
1212
|
+
var command2 = Command5.make(
|
|
1201
1213
|
"run",
|
|
1202
1214
|
{
|
|
1203
1215
|
data: dataOption,
|
|
1204
|
-
encodedCommand:
|
|
1205
|
-
|
|
1206
|
-
|
|
1216
|
+
encodedCommand: Flag.string("encoded-command").pipe(
|
|
1217
|
+
Flag.optional,
|
|
1218
|
+
Flag.withHidden
|
|
1207
1219
|
),
|
|
1208
1220
|
args: Argument3.string("command").pipe(
|
|
1209
1221
|
Argument3.withDescription("The command to run"),
|
|
@@ -1211,11 +1223,11 @@ var command2 = Command6.make(
|
|
|
1211
1223
|
)
|
|
1212
1224
|
},
|
|
1213
1225
|
({ args, data, encodedCommand }) => Effect10.gen(function* () {
|
|
1214
|
-
const resolvedArgs =
|
|
1226
|
+
const resolvedArgs = Option4.isSome(encodedCommand) ? JSON.parse(Buffer.from(encodedCommand.value, "base64url").toString("utf8")) : args;
|
|
1215
1227
|
const [rawExecutable, ...commandArgs] = resolvedArgs;
|
|
1216
1228
|
const executable = rawExecutable === "node" ? process.execPath : rawExecutable;
|
|
1217
1229
|
const runId = yield* RunId;
|
|
1218
|
-
yield* Console2.log(`Run ID: ${runId}`);
|
|
1230
|
+
yield* Console2.log(`Inspeffct Run ID: ${runId}`);
|
|
1219
1231
|
yield* Effect10.logDebug(`Running: ${executable} ${commandArgs.join(" ")}`);
|
|
1220
1232
|
yield* Effect10.logDebug(`Data file: ${data}`);
|
|
1221
1233
|
const bootloaderPath = yield* getPath;
|
|
@@ -1268,7 +1280,19 @@ var command2 = Command6.make(
|
|
|
1268
1280
|
Effect10.scoped,
|
|
1269
1281
|
Effect10.provide(makeServicesLayer(data))
|
|
1270
1282
|
)
|
|
1271
|
-
).pipe(
|
|
1283
|
+
).pipe(
|
|
1284
|
+
Command5.withDescription("Run a command with Effect instrumentation"),
|
|
1285
|
+
Command5.withExamples([
|
|
1286
|
+
{
|
|
1287
|
+
command: "inspeffct run -- node app.js",
|
|
1288
|
+
description: "Run a Node.js application with instrumentation"
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
command: "inspeffct run --data .inspeffct.db -- node --inspect app.js",
|
|
1292
|
+
description: "Capture data in a specific SQLite database"
|
|
1293
|
+
}
|
|
1294
|
+
])
|
|
1295
|
+
);
|
|
1272
1296
|
var getSpanId = (span) => span.spanId;
|
|
1273
1297
|
var getTraceId = (span) => span.traceId;
|
|
1274
1298
|
var getParentSpanId = (span) => span._tag === "Span" ? span.parentSpanId : null;
|
|
@@ -1321,6 +1345,7 @@ var formatStatusDoc = (status) => {
|
|
|
1321
1345
|
}
|
|
1322
1346
|
};
|
|
1323
1347
|
var field = (label, value) => `${label}: ${value}`;
|
|
1348
|
+
var dim = (text) => `\x1B[2m${text}\x1B[22m`;
|
|
1324
1349
|
var renderDoc = (doc) => doc;
|
|
1325
1350
|
var statusSymbol = (status, hasEndTime) => {
|
|
1326
1351
|
if (!hasEndTime) {
|
|
@@ -1360,14 +1385,29 @@ var formatSpanLine = (span) => {
|
|
|
1360
1385
|
const duration = endTime !== null ? formatDuration(endTime - startTime) : "running";
|
|
1361
1386
|
return `${symbol} ${getSpanName(span)} (${duration}) [${getSpanId(span)}]`;
|
|
1362
1387
|
};
|
|
1388
|
+
var formatAttributeValue = (value) => {
|
|
1389
|
+
const json = JSON.stringify(value);
|
|
1390
|
+
return json === void 0 ? "undefined" : json;
|
|
1391
|
+
};
|
|
1392
|
+
var formatSpanAttributesLine = (span) => {
|
|
1393
|
+
const attributes = Object.entries(getAttributes(span));
|
|
1394
|
+
if (attributes.length === 0) {
|
|
1395
|
+
return null;
|
|
1396
|
+
}
|
|
1397
|
+
const rendered = attributes.slice(0, 3).map(([key, value]) => `${key}=${formatAttributeValue(value)}`);
|
|
1398
|
+
if (attributes.length > 3) {
|
|
1399
|
+
rendered.push("...");
|
|
1400
|
+
}
|
|
1401
|
+
return rendered.join(", ");
|
|
1402
|
+
};
|
|
1363
1403
|
var renderGraphNode = (graph, nodeIndex, prefix, isLast, isRoot) => {
|
|
1364
1404
|
const spanOpt = Graph.getNode(graph, nodeIndex);
|
|
1365
|
-
if (
|
|
1405
|
+
if (Option4.isNone(spanOpt)) return "";
|
|
1366
1406
|
const span = spanOpt.value;
|
|
1367
1407
|
const children = [];
|
|
1368
1408
|
for (const childIndex of Graph.neighbors(graph, nodeIndex)) {
|
|
1369
1409
|
const childSpanOpt = Graph.getNode(graph, childIndex);
|
|
1370
|
-
if (
|
|
1410
|
+
if (Option4.isSome(childSpanOpt)) {
|
|
1371
1411
|
children.push({ index: childIndex, span: childSpanOpt.value });
|
|
1372
1412
|
}
|
|
1373
1413
|
}
|
|
@@ -1375,10 +1415,13 @@ var renderGraphNode = (graph, nodeIndex, prefix, isLast, isRoot) => {
|
|
|
1375
1415
|
const connector = isRoot ? "" : isLast ? "\u2514\u2500 " : "\u251C\u2500 ";
|
|
1376
1416
|
const line = `${prefix}${connector}${formatSpanLine(span)}`;
|
|
1377
1417
|
const childPrefix = isRoot ? "" : prefix + (isLast ? " " : "\u2502 ");
|
|
1418
|
+
const attributePrefix = isRoot ? " " : `${childPrefix} `;
|
|
1419
|
+
const attributesLine = formatSpanAttributesLine(span);
|
|
1420
|
+
const attributeDoc = attributesLine === null ? [] : [`${attributePrefix}${dim(attributesLine)}`];
|
|
1378
1421
|
const childDocs = children.map(
|
|
1379
1422
|
(child, i) => renderGraphNode(graph, child.index, childPrefix, i === children.length - 1, false)
|
|
1380
1423
|
);
|
|
1381
|
-
return [line, ...childDocs.filter((doc) => doc.length > 0)].join("\n");
|
|
1424
|
+
return [line, ...attributeDoc, ...childDocs.filter((doc) => doc.length > 0)].join("\n");
|
|
1382
1425
|
};
|
|
1383
1426
|
var renderSpanGraph = (graph) => {
|
|
1384
1427
|
const roots = [];
|
|
@@ -1395,7 +1438,10 @@ var renderSpanGraph = (graph) => {
|
|
|
1395
1438
|
|
|
1396
1439
|
// src/cli/span.ts
|
|
1397
1440
|
var attributesToObject = (attributes) => Object.fromEntries(attributes);
|
|
1398
|
-
var
|
|
1441
|
+
var getSpanExit = (span) => span._tag === "Span" && span.status._tag === "Ended" ? span.status.exit : null;
|
|
1442
|
+
var stringifyJson = (value) => JSON.stringify(value, (_key, value2) => typeof value2 === "bigint" ? value2.toString() : value2, 2);
|
|
1443
|
+
var formatExitBlock = (exit) => ["Exit:", ...stringifyJson(exit).split("\n").map((line) => ` ${line}`)].join("\n");
|
|
1444
|
+
var command3 = Command5.make(
|
|
1399
1445
|
"span",
|
|
1400
1446
|
{
|
|
1401
1447
|
data: dataOption,
|
|
@@ -1420,6 +1466,7 @@ var command3 = Command6.make(
|
|
|
1420
1466
|
const startTime = getStartTime(span);
|
|
1421
1467
|
const endTime = getEndTime(span);
|
|
1422
1468
|
const durationNanos = endTime !== null ? endTime - startTime : null;
|
|
1469
|
+
const exit = getSpanExit(span);
|
|
1423
1470
|
if (json) {
|
|
1424
1471
|
const output = {
|
|
1425
1472
|
span: {
|
|
@@ -1434,6 +1481,7 @@ var command3 = Command6.make(
|
|
|
1434
1481
|
endTime: endTime !== null ? formatTimestamp(endTime) : null,
|
|
1435
1482
|
durationMs: durationNanos !== null ? Number(durationNanos / 1000000n) : null,
|
|
1436
1483
|
attributes: getAttributes(span),
|
|
1484
|
+
exit,
|
|
1437
1485
|
isExternal: isExternalSpan(span)
|
|
1438
1486
|
},
|
|
1439
1487
|
events: events.map((event) => ({
|
|
@@ -1473,6 +1521,9 @@ var command3 = Command6.make(
|
|
|
1473
1521
|
if (Object.keys(attrs).length > 0) {
|
|
1474
1522
|
fields.push(field("Attrs", JSON.stringify(attrs)));
|
|
1475
1523
|
}
|
|
1524
|
+
if (exit !== null) {
|
|
1525
|
+
fields.push(formatExitBlock(exit));
|
|
1526
|
+
}
|
|
1476
1527
|
const eventDocs = events.length === 0 ? ["Events: none"] : [
|
|
1477
1528
|
`Events (${events.length}):`,
|
|
1478
1529
|
...events.map((event) => {
|
|
@@ -1501,128 +1552,20 @@ var command3 = Command6.make(
|
|
|
1501
1552
|
Effect10.scoped,
|
|
1502
1553
|
Effect10.provide(makeReadOnlyLayer(data))
|
|
1503
1554
|
)
|
|
1504
|
-
).pipe(
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
limit: limitOption,
|
|
1515
|
-
minDuration: Flag3.string("min-duration").pipe(
|
|
1516
|
-
Flag3.withDescription("Filter by minimum duration (e.g., '100ms', '1s')"),
|
|
1517
|
-
Flag3.optional
|
|
1518
|
-
),
|
|
1519
|
-
name: Flag3.string("name").pipe(
|
|
1520
|
-
Flag3.withDescription("Filter by span name (use % for wildcards)"),
|
|
1521
|
-
Flag3.optional
|
|
1522
|
-
),
|
|
1523
|
-
spanId: Flag3.string("span-id").pipe(
|
|
1524
|
-
Flag3.withDescription("Filter by span ID"),
|
|
1525
|
-
Flag3.optional
|
|
1526
|
-
),
|
|
1527
|
-
status: Flag3.string("status").pipe(
|
|
1528
|
-
Flag3.withDescription("Filter by status: ok, error, unset"),
|
|
1529
|
-
Flag3.optional
|
|
1530
|
-
),
|
|
1531
|
-
trace: Flag3.string("trace-id").pipe(
|
|
1532
|
-
Flag3.withAlias("t"),
|
|
1533
|
-
Flag3.withDescription("Filter by trace ID"),
|
|
1534
|
-
Flag3.optional
|
|
1535
|
-
)
|
|
1536
|
-
},
|
|
1537
|
-
({ data, json, limit, minDuration, name, runId, spanId, status, trace }) => Effect10.gen(function* () {
|
|
1538
|
-
const storage = yield* Storage;
|
|
1539
|
-
let statusCode;
|
|
1540
|
-
if (Option3.isSome(status)) {
|
|
1541
|
-
switch (status.value) {
|
|
1542
|
-
case "ok":
|
|
1543
|
-
statusCode = 1;
|
|
1544
|
-
break;
|
|
1545
|
-
case "error":
|
|
1546
|
-
statusCode = 2;
|
|
1547
|
-
break;
|
|
1548
|
-
case "unset":
|
|
1549
|
-
statusCode = 0;
|
|
1550
|
-
break;
|
|
1551
|
-
default:
|
|
1552
|
-
yield* Effect10.logWarning(`Unknown status: ${status.value}, ignoring filter`);
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
const filters = {
|
|
1556
|
-
...Option3.isSome(runId) ? { runId: runId.value } : {},
|
|
1557
|
-
...Option3.isSome(spanId) ? { spanId: spanId.value } : {},
|
|
1558
|
-
...Option3.isSome(trace) ? { traceId: trace.value } : {},
|
|
1559
|
-
...Option3.isSome(name) ? { name: name.value } : {},
|
|
1560
|
-
...statusCode !== void 0 ? { status: statusCode } : {},
|
|
1561
|
-
...Option3.isSome(minDuration) ? { minDuration: parseDurationToNanos(minDuration.value) } : {},
|
|
1562
|
-
...Option3.isSome(limit) ? { limit: limit.value } : {}
|
|
1563
|
-
};
|
|
1564
|
-
const spans = yield* storage.getSpans(filters);
|
|
1565
|
-
if (json) {
|
|
1566
|
-
const output = spans.map((s) => {
|
|
1567
|
-
const endTime = getEndTime(s);
|
|
1568
|
-
const startTime = getStartTime(s);
|
|
1569
|
-
return {
|
|
1570
|
-
spanId: getSpanId(s),
|
|
1571
|
-
traceId: getTraceId(s),
|
|
1572
|
-
parentSpanId: getParentSpanId(s),
|
|
1573
|
-
name: getSpanName(s),
|
|
1574
|
-
kind: getSpanKind(s),
|
|
1575
|
-
statusCode: getStatusCode(s),
|
|
1576
|
-
statusMessage: getStatusMessage(s),
|
|
1577
|
-
startTime: formatTimestamp(startTime),
|
|
1578
|
-
endTime: endTime !== null ? formatTimestamp(endTime) : null,
|
|
1579
|
-
durationMs: endTime !== null ? Number((endTime - startTime) / 1000000n) : null,
|
|
1580
|
-
attributes: getAttributes(s),
|
|
1581
|
-
isExternal: isExternalSpan(s)
|
|
1582
|
-
};
|
|
1583
|
-
});
|
|
1584
|
-
yield* Console2.log(JSON.stringify(output, null, 2));
|
|
1585
|
-
} else {
|
|
1586
|
-
if (spans.length === 0) {
|
|
1587
|
-
yield* Console2.log("No spans found.");
|
|
1588
|
-
} else {
|
|
1589
|
-
const spanItems = spans.map((s) => {
|
|
1590
|
-
const endTime = getEndTime(s);
|
|
1591
|
-
const startTime = getStartTime(s);
|
|
1592
|
-
const duration = endTime !== null ? formatDuration(endTime - startTime) : "running";
|
|
1593
|
-
const fields = [
|
|
1594
|
-
field("Name", getSpanName(s)),
|
|
1595
|
-
field("Trace", getTraceId(s))
|
|
1596
|
-
];
|
|
1597
|
-
const parentSpanId = getParentSpanId(s);
|
|
1598
|
-
if (parentSpanId) {
|
|
1599
|
-
fields.push(field("Parent", parentSpanId));
|
|
1600
|
-
}
|
|
1601
|
-
fields.push(
|
|
1602
|
-
field("Status", formatStatusDoc(getStatusCode(s))),
|
|
1603
|
-
field("Started", formatTimestamp(startTime)),
|
|
1604
|
-
field("Duration", duration)
|
|
1605
|
-
);
|
|
1606
|
-
const attrs = getAttributes(s);
|
|
1607
|
-
if (Object.keys(attrs).length > 0) {
|
|
1608
|
-
fields.push(field("Attrs", JSON.stringify(attrs)));
|
|
1609
|
-
}
|
|
1610
|
-
return [getSpanId(s), ...fields.map((field2) => ` ${field2}`)].join("\n");
|
|
1611
|
-
});
|
|
1612
|
-
const doc = [
|
|
1613
|
-
`Found ${spans.length} span(s):`,
|
|
1614
|
-
"",
|
|
1615
|
-
...spanItems
|
|
1616
|
-
].join("\n");
|
|
1617
|
-
yield* Console2.log(renderDoc(doc));
|
|
1618
|
-
}
|
|
1555
|
+
).pipe(
|
|
1556
|
+
Command5.withDescription("Show detailed span information"),
|
|
1557
|
+
Command5.withExamples([
|
|
1558
|
+
{
|
|
1559
|
+
command: "inspeffct span <trace-id> <span-id>",
|
|
1560
|
+
description: "Show span details with events and links"
|
|
1561
|
+
},
|
|
1562
|
+
{
|
|
1563
|
+
command: "inspeffct span --json <trace-id> <span-id>",
|
|
1564
|
+
description: "Print span details as JSON"
|
|
1619
1565
|
}
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
)
|
|
1624
|
-
).pipe(Command6.withDescription("List spans with optional filters"));
|
|
1625
|
-
var command5 = Command6.make(
|
|
1566
|
+
])
|
|
1567
|
+
);
|
|
1568
|
+
var command4 = Command5.make(
|
|
1626
1569
|
"trace",
|
|
1627
1570
|
{
|
|
1628
1571
|
data: dataOption,
|
|
@@ -1644,7 +1587,7 @@ var command5 = Command6.make(
|
|
|
1644
1587
|
if (json) {
|
|
1645
1588
|
const buildJsonTree = (g, nodeIndex) => {
|
|
1646
1589
|
const spanOpt = Graph.getNode(g, nodeIndex);
|
|
1647
|
-
if (
|
|
1590
|
+
if (Option4.isNone(spanOpt)) return {};
|
|
1648
1591
|
const span = spanOpt.value;
|
|
1649
1592
|
const endTime = getEndTime(span);
|
|
1650
1593
|
const startTime = getStartTime(span);
|
|
@@ -1652,7 +1595,7 @@ var command5 = Command6.make(
|
|
|
1652
1595
|
const children = [];
|
|
1653
1596
|
for (const childIndex of Graph.neighbors(g, nodeIndex)) {
|
|
1654
1597
|
const childSpanOpt = Graph.getNode(g, childIndex);
|
|
1655
|
-
if (
|
|
1598
|
+
if (Option4.isSome(childSpanOpt)) {
|
|
1656
1599
|
children.push({ index: childIndex, span: childSpanOpt.value });
|
|
1657
1600
|
}
|
|
1658
1601
|
}
|
|
@@ -1691,30 +1634,42 @@ var command5 = Command6.make(
|
|
|
1691
1634
|
Effect10.scoped,
|
|
1692
1635
|
Effect10.provide(makeReadOnlyLayer(data))
|
|
1693
1636
|
)
|
|
1694
|
-
).pipe(
|
|
1695
|
-
|
|
1637
|
+
).pipe(
|
|
1638
|
+
Command5.withDescription("Show a trace and all spans related to that trace as a tree view"),
|
|
1639
|
+
Command5.withExamples([
|
|
1640
|
+
{
|
|
1641
|
+
command: "inspeffct trace <trace-id>",
|
|
1642
|
+
description: "Show the trace tree with related spans"
|
|
1643
|
+
},
|
|
1644
|
+
{
|
|
1645
|
+
command: "inspeffct trace --json <trace-id>",
|
|
1646
|
+
description: "Print the trace tree as JSON"
|
|
1647
|
+
}
|
|
1648
|
+
])
|
|
1649
|
+
);
|
|
1650
|
+
var command5 = Command5.make(
|
|
1696
1651
|
"traces",
|
|
1697
1652
|
{
|
|
1698
1653
|
data: dataOption,
|
|
1699
1654
|
json: jsonOption,
|
|
1700
|
-
runId:
|
|
1701
|
-
|
|
1702
|
-
|
|
1655
|
+
runId: Flag.string("run-id").pipe(
|
|
1656
|
+
Flag.withDescription("Filter by run ID"),
|
|
1657
|
+
Flag.optional
|
|
1703
1658
|
),
|
|
1704
1659
|
limit: limitOption,
|
|
1705
|
-
since:
|
|
1706
|
-
|
|
1707
|
-
|
|
1660
|
+
since: Flag.string("since").pipe(
|
|
1661
|
+
Flag.withDescription("Filter by time range (e.g., '1h', '30m')"),
|
|
1662
|
+
Flag.optional
|
|
1708
1663
|
),
|
|
1709
|
-
status:
|
|
1710
|
-
|
|
1711
|
-
|
|
1664
|
+
status: Flag.string("status").pipe(
|
|
1665
|
+
Flag.withDescription("Filter by status: ok, error, unset"),
|
|
1666
|
+
Flag.optional
|
|
1712
1667
|
)
|
|
1713
1668
|
},
|
|
1714
1669
|
({ data, json, limit, runId, since, status }) => Effect10.gen(function* () {
|
|
1715
1670
|
const storage = yield* Storage;
|
|
1716
1671
|
let statusCode;
|
|
1717
|
-
if (
|
|
1672
|
+
if (Option4.isSome(status)) {
|
|
1718
1673
|
switch (status.value) {
|
|
1719
1674
|
case "ok":
|
|
1720
1675
|
statusCode = 1;
|
|
@@ -1730,16 +1685,16 @@ var command6 = Command6.make(
|
|
|
1730
1685
|
}
|
|
1731
1686
|
}
|
|
1732
1687
|
let sinceNanos;
|
|
1733
|
-
if (
|
|
1688
|
+
if (Option4.isSome(since)) {
|
|
1734
1689
|
const nowNanos = BigInt(Date.now()) * 1000000n;
|
|
1735
1690
|
const durationNanos = parseDurationToNanos(since.value);
|
|
1736
1691
|
sinceNanos = nowNanos - durationNanos;
|
|
1737
1692
|
}
|
|
1738
1693
|
const filters = {
|
|
1739
|
-
...
|
|
1694
|
+
...Option4.isSome(runId) ? { runId: runId.value } : {},
|
|
1740
1695
|
...statusCode !== void 0 ? { status: statusCode } : {},
|
|
1741
1696
|
...sinceNanos !== void 0 ? { since: sinceNanos } : {},
|
|
1742
|
-
...
|
|
1697
|
+
...Option4.isSome(limit) ? { limit: limit.value } : {}
|
|
1743
1698
|
};
|
|
1744
1699
|
const traces = yield* storage.getTraces(filters);
|
|
1745
1700
|
if (json) {
|
|
@@ -1780,17 +1735,35 @@ var command6 = Command6.make(
|
|
|
1780
1735
|
Effect10.scoped,
|
|
1781
1736
|
Effect10.provide(makeReadOnlyLayer(data))
|
|
1782
1737
|
)
|
|
1783
|
-
).pipe(
|
|
1738
|
+
).pipe(
|
|
1739
|
+
Command5.withDescription("List traces with optional filters"),
|
|
1740
|
+
Command5.withExamples([
|
|
1741
|
+
{
|
|
1742
|
+
command: "inspeffct traces",
|
|
1743
|
+
description: "List recent traces"
|
|
1744
|
+
},
|
|
1745
|
+
{
|
|
1746
|
+
command: "inspeffct traces --run-id <run-id>",
|
|
1747
|
+
description: "List traces captured during a specific run"
|
|
1748
|
+
},
|
|
1749
|
+
{
|
|
1750
|
+
command: "inspeffct traces --status error --since 1h",
|
|
1751
|
+
description: "List recent traces that contain errors"
|
|
1752
|
+
}
|
|
1753
|
+
])
|
|
1754
|
+
);
|
|
1784
1755
|
|
|
1785
1756
|
// src/cli.ts
|
|
1786
|
-
var
|
|
1787
|
-
|
|
1788
|
-
|
|
1757
|
+
var command6 = Command5.make("inspeffct").pipe(
|
|
1758
|
+
Command5.withDescription(
|
|
1759
|
+
"Run your Effect application with `npx inspeffct run ...` to start capturing data, and then inspect data with the CLI."
|
|
1760
|
+
),
|
|
1761
|
+
Command5.withSubcommands([
|
|
1789
1762
|
{ group: "Capture", commands: [command2, command] },
|
|
1790
|
-
{ group: "Inspect", commands: [
|
|
1763
|
+
{ group: "Inspect", commands: [command5, command4, command3] }
|
|
1791
1764
|
])
|
|
1792
1765
|
);
|
|
1793
|
-
var cli =
|
|
1766
|
+
var cli = Command5.runWith(command6, {
|
|
1794
1767
|
version: "0.0.1"
|
|
1795
1768
|
});
|
|
1796
1769
|
var encodeRunSeparator = (args) => {
|