inspeffct 1.0.4 → 1.0.6
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 +277 -64
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
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
|
|
6
|
-
import * as
|
|
5
|
+
import * as Command6 from 'effect/unstable/cli/Command';
|
|
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';
|
|
9
9
|
import * as FileSystem from 'effect/FileSystem';
|
|
@@ -332,9 +332,9 @@ var randomUUID = Effect10.gen(function* () {
|
|
|
332
332
|
hex.slice(10, 16).join("")
|
|
333
333
|
].join("-");
|
|
334
334
|
});
|
|
335
|
-
var
|
|
335
|
+
var RunId = class extends Context4.Service()("inspeffct/RunId") {
|
|
336
336
|
};
|
|
337
|
-
var layer3 = Layer8.effect(
|
|
337
|
+
var layer3 = Layer8.effect(RunId, randomUUID);
|
|
338
338
|
var isSchema = (u) => typeof u === "object" && u !== null && "ast" in u;
|
|
339
339
|
var getMembers = (schema) => "members" in schema && Array.isArray(schema.members) ? schema.members : "cases" in schema ? Object.values(schema.cases) : [schema];
|
|
340
340
|
var evolveNested = (schema, evolve2) => {
|
|
@@ -516,13 +516,13 @@ var create_otel_tables_default = Effect10.gen(function* () {
|
|
|
516
516
|
});
|
|
517
517
|
var create_span_exits_table_default = Effect10.void;
|
|
518
518
|
var simplify_span_exits_default = Effect10.void;
|
|
519
|
-
var
|
|
519
|
+
var add_run_id_default = Effect10.gen(function* () {
|
|
520
520
|
const sql = yield* SqlClient5.SqlClient;
|
|
521
|
-
yield* sql`ALTER TABLE spans ADD COLUMN
|
|
522
|
-
Effect10.withSpan("
|
|
521
|
+
yield* sql`ALTER TABLE spans ADD COLUMN run_id TEXT NOT NULL DEFAULT ''`.pipe(
|
|
522
|
+
Effect10.withSpan("add_spans_run_id")
|
|
523
523
|
);
|
|
524
|
-
yield* sql`CREATE INDEX
|
|
525
|
-
Effect10.withSpan("
|
|
524
|
+
yield* sql`CREATE INDEX idx_spans_run_id ON spans(run_id)`.pipe(
|
|
525
|
+
Effect10.withSpan("create_idx_spans_run_id")
|
|
526
526
|
);
|
|
527
527
|
});
|
|
528
528
|
|
|
@@ -594,7 +594,7 @@ var DbExternalSpan = ExternalSpan.pipe(
|
|
|
594
594
|
);
|
|
595
595
|
var DbAnySpan = Schema.Union([DbSpan, DbExternalSpan]);
|
|
596
596
|
var TraceSummary = Schema.Struct({
|
|
597
|
-
|
|
597
|
+
run_id: Schema.String,
|
|
598
598
|
trace_id: Schema.String,
|
|
599
599
|
span_count: NumberFromBigInt,
|
|
600
600
|
root_span_name: Schema.NullOr(Schema.String),
|
|
@@ -620,7 +620,7 @@ var MigrationsLoader = Migrator.fromRecord({
|
|
|
620
620
|
"0001_create_otel_tables": create_otel_tables_default,
|
|
621
621
|
"0002_create_span_exits_table": create_span_exits_table_default,
|
|
622
622
|
"0003_simplify_span_exits": simplify_span_exits_default,
|
|
623
|
-
"
|
|
623
|
+
"0004_add_run_id": add_run_id_default
|
|
624
624
|
});
|
|
625
625
|
var runMigrations = Migrator.make({})({
|
|
626
626
|
loader: MigrationsLoader
|
|
@@ -630,14 +630,14 @@ var layer5 = (config) => Layer8.effectContext(
|
|
|
630
630
|
const sql = yield* SqliteClient.SqliteClient;
|
|
631
631
|
yield* runMigrations;
|
|
632
632
|
const storage = Storage.of({
|
|
633
|
-
persistSpan: (span,
|
|
633
|
+
persistSpan: (span, runId) => Effect10.gen(function* () {
|
|
634
634
|
const changed = yield* (
|
|
635
635
|
// @ts-ignore TS28 false positive from SqlSchema service inference
|
|
636
636
|
SqlSchema.findOne({
|
|
637
637
|
Request: DbAnySpan,
|
|
638
638
|
Result: Schema.Struct({ span_id: Schema.String }),
|
|
639
639
|
execute: (db) => {
|
|
640
|
-
const row = { ...db,
|
|
640
|
+
const row = { ...db, run_id: runId };
|
|
641
641
|
return sql`
|
|
642
642
|
INSERT INTO spans ${sql.insert(row)}
|
|
643
643
|
ON CONFLICT(span_id) DO UPDATE SET
|
|
@@ -756,22 +756,22 @@ var layer5 = (config) => Layer8.effectContext(
|
|
|
756
756
|
}),
|
|
757
757
|
getTraces: (filters = {}) => SqlSchema.findAll({
|
|
758
758
|
Request: Schema.Struct({
|
|
759
|
-
executionId: Schema.optional(Schema.String),
|
|
760
759
|
limit: Schema.optional(Schema.Number),
|
|
760
|
+
runId: Schema.optional(Schema.String),
|
|
761
761
|
since: Schema.optional(Schema.BigInt),
|
|
762
762
|
status: Schema.optional(Schema.Number)
|
|
763
763
|
}),
|
|
764
764
|
Result: TraceSummary,
|
|
765
765
|
execute: (req) => sql`
|
|
766
766
|
SELECT
|
|
767
|
-
s.
|
|
767
|
+
s.run_id,
|
|
768
768
|
s.trace_id,
|
|
769
769
|
COUNT(*) as span_count,
|
|
770
770
|
(
|
|
771
771
|
SELECT name
|
|
772
772
|
FROM spans
|
|
773
773
|
WHERE trace_id = s.trace_id
|
|
774
|
-
AND
|
|
774
|
+
AND run_id = s.run_id
|
|
775
775
|
AND parent_span_id IS NULL
|
|
776
776
|
LIMIT 1
|
|
777
777
|
) as root_span_name,
|
|
@@ -786,7 +786,7 @@ var layer5 = (config) => Layer8.effectContext(
|
|
|
786
786
|
) as status
|
|
787
787
|
FROM spans s
|
|
788
788
|
WHERE ${sql.and([
|
|
789
|
-
req.
|
|
789
|
+
req.runId !== void 0 ? sql`s.run_id = ${req.runId}` : sql`1=1`,
|
|
790
790
|
req.since !== void 0 ? sql`s.start_time >= ${req.since}` : sql`1=1`,
|
|
791
791
|
req.status !== void 0 ? sql`
|
|
792
792
|
CASE
|
|
@@ -796,7 +796,7 @@ var layer5 = (config) => Layer8.effectContext(
|
|
|
796
796
|
END = ${req.status}
|
|
797
797
|
` : sql`1=1`
|
|
798
798
|
])}
|
|
799
|
-
GROUP BY s.
|
|
799
|
+
GROUP BY s.run_id, s.trace_id
|
|
800
800
|
ORDER BY start_time DESC
|
|
801
801
|
${req.limit !== void 0 ? sql`LIMIT ${req.limit}` : sql``}
|
|
802
802
|
`
|
|
@@ -807,10 +807,11 @@ var layer5 = (config) => Layer8.effectContext(
|
|
|
807
807
|
// @ts-ignore TS28 false positive from SqlSchema service inference
|
|
808
808
|
SqlSchema.findAll({
|
|
809
809
|
Request: Schema.Struct({
|
|
810
|
-
executionId: Schema.optional(Schema.String),
|
|
811
810
|
limit: Schema.optional(Schema.Number),
|
|
812
811
|
minDuration: Schema.optional(Schema.BigInt),
|
|
813
812
|
name: Schema.optional(Schema.String),
|
|
813
|
+
runId: Schema.optional(Schema.String),
|
|
814
|
+
spanId: Schema.optional(Schema.String),
|
|
814
815
|
status: Schema.optional(Schema.Number),
|
|
815
816
|
traceId: Schema.optional(Schema.String)
|
|
816
817
|
}),
|
|
@@ -819,7 +820,8 @@ var layer5 = (config) => Layer8.effectContext(
|
|
|
819
820
|
SELECT s.*
|
|
820
821
|
FROM spans s
|
|
821
822
|
WHERE ${sql.and([
|
|
822
|
-
req.
|
|
823
|
+
req.runId !== void 0 ? sql`s.run_id = ${req.runId}` : sql`1=1`,
|
|
824
|
+
req.spanId !== void 0 ? sql`s.span_id = ${req.spanId}` : sql`1=1`,
|
|
823
825
|
req.traceId !== void 0 ? sql`s.trace_id = ${req.traceId}` : sql`1=1`,
|
|
824
826
|
req.name !== void 0 ? req.name.includes("%") ? sql`s.name LIKE ${req.name}` : sql`s.name = ${req.name}` : sql`1=1`,
|
|
825
827
|
req.minDuration !== void 0 ? sql`(s.end_time - s.start_time) >= ${req.minDuration}` : sql`1=1`,
|
|
@@ -849,7 +851,7 @@ var EventCollector = class extends Context4.Service()("inspeffct/EventCollector"
|
|
|
849
851
|
var layer6 = Layer8.effect(
|
|
850
852
|
EventCollector,
|
|
851
853
|
Effect10.gen(function* () {
|
|
852
|
-
const
|
|
854
|
+
const runId = yield* RunId;
|
|
853
855
|
const storage = yield* Storage;
|
|
854
856
|
return EventCollector.of({
|
|
855
857
|
collect: (message) => Effect10.gen(function* () {
|
|
@@ -863,12 +865,10 @@ var layer6 = Layer8.effect(
|
|
|
863
865
|
case "TracerSpanNotification": {
|
|
864
866
|
const { instrumentationId, span } = message;
|
|
865
867
|
yield* Effect10.logDebug(`${message._tag} from ${instrumentationId}`);
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
);
|
|
871
|
-
}
|
|
868
|
+
yield* storage.persistSpan(span, runId);
|
|
869
|
+
yield* Effect10.logDebug(
|
|
870
|
+
`Persisted span (${span.traceId}, ${span.spanId}) to storage`
|
|
871
|
+
);
|
|
872
872
|
break;
|
|
873
873
|
}
|
|
874
874
|
case "TracerSpanEventNotification": {
|
|
@@ -1139,16 +1139,16 @@ var buildEnv = (bootloaderPath, ipcPath) => {
|
|
|
1139
1139
|
};
|
|
1140
1140
|
};
|
|
1141
1141
|
var makeServicesLayer = (dataPath) => {
|
|
1142
|
-
const
|
|
1142
|
+
const runIdLayer = layer3;
|
|
1143
1143
|
const storageLayer = layer5({ filename: dataPath });
|
|
1144
1144
|
const eventCollectorLayer = layer6.pipe(
|
|
1145
|
-
Layer8.provide(
|
|
1145
|
+
Layer8.provide(runIdLayer),
|
|
1146
1146
|
Layer8.provide(storageLayer)
|
|
1147
1147
|
);
|
|
1148
1148
|
const bootloaderPathLayer = layer.pipe(Layer8.provide(NodePath.layer));
|
|
1149
1149
|
return Layer8.mergeAll(
|
|
1150
|
-
executionIdLayer,
|
|
1151
1150
|
layer8,
|
|
1151
|
+
runIdLayer,
|
|
1152
1152
|
bootloaderPathLayer,
|
|
1153
1153
|
layer7.pipe(
|
|
1154
1154
|
Layer8.provide(layer2),
|
|
@@ -1163,12 +1163,12 @@ 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 = Command6.make(
|
|
1167
1167
|
"connect",
|
|
1168
1168
|
{
|
|
1169
1169
|
data: dataOption,
|
|
1170
|
-
url:
|
|
1171
|
-
|
|
1170
|
+
url: Argument3.string("url").pipe(
|
|
1171
|
+
Argument3.withDescription("WebSocket URL of the inspector (ws://...)")
|
|
1172
1172
|
)
|
|
1173
1173
|
},
|
|
1174
1174
|
({ data, url }) => Effect10.gen(function* () {
|
|
@@ -1182,7 +1182,19 @@ var command = Command5.make(
|
|
|
1182
1182
|
Effect10.scoped,
|
|
1183
1183
|
Effect10.provide(makeServicesLayer(data))
|
|
1184
1184
|
)
|
|
1185
|
-
).pipe(
|
|
1185
|
+
).pipe(
|
|
1186
|
+
Command6.withDescription("Connect to an existing CDP inspector endpoint"),
|
|
1187
|
+
Command6.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,7 +1209,7 @@ var parseInspectorUrl = (chunk, decoder) => {
|
|
|
1197
1209
|
}
|
|
1198
1210
|
return void 0;
|
|
1199
1211
|
};
|
|
1200
|
-
var command2 =
|
|
1212
|
+
var command2 = Command6.make(
|
|
1201
1213
|
"run",
|
|
1202
1214
|
{
|
|
1203
1215
|
data: dataOption,
|
|
@@ -1205,17 +1217,17 @@ var command2 = Command5.make(
|
|
|
1205
1217
|
Flag3.optional,
|
|
1206
1218
|
Flag3.withHidden
|
|
1207
1219
|
),
|
|
1208
|
-
args:
|
|
1209
|
-
|
|
1210
|
-
|
|
1220
|
+
args: Argument3.string("command").pipe(
|
|
1221
|
+
Argument3.withDescription("The command to run"),
|
|
1222
|
+
Argument3.variadic({ min: 0 })
|
|
1211
1223
|
)
|
|
1212
1224
|
},
|
|
1213
1225
|
({ args, data, encodedCommand }) => Effect10.gen(function* () {
|
|
1214
1226
|
const resolvedArgs = Option3.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
|
-
const
|
|
1218
|
-
yield* Console2.log(`
|
|
1229
|
+
const runId = yield* 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 = Command5.make(
|
|
|
1268
1280
|
Effect10.scoped,
|
|
1269
1281
|
Effect10.provide(makeServicesLayer(data))
|
|
1270
1282
|
)
|
|
1271
|
-
).pipe(
|
|
1283
|
+
).pipe(
|
|
1284
|
+
Command6.withDescription("Run a command with Effect instrumentation"),
|
|
1285
|
+
Command6.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,6 +1385,17 @@ 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
|
+
return attributes.map(([key, value]) => `${key}=${formatAttributeValue(value)}`).join(", ");
|
|
1398
|
+
};
|
|
1363
1399
|
var renderGraphNode = (graph, nodeIndex, prefix, isLast, isRoot) => {
|
|
1364
1400
|
const spanOpt = Graph.getNode(graph, nodeIndex);
|
|
1365
1401
|
if (Option3.isNone(spanOpt)) return "";
|
|
@@ -1375,10 +1411,13 @@ var renderGraphNode = (graph, nodeIndex, prefix, isLast, isRoot) => {
|
|
|
1375
1411
|
const connector = isRoot ? "" : isLast ? "\u2514\u2500 " : "\u251C\u2500 ";
|
|
1376
1412
|
const line = `${prefix}${connector}${formatSpanLine(span)}`;
|
|
1377
1413
|
const childPrefix = isRoot ? "" : prefix + (isLast ? " " : "\u2502 ");
|
|
1414
|
+
const attributePrefix = isRoot ? " " : `${childPrefix} `;
|
|
1415
|
+
const attributesLine = formatSpanAttributesLine(span);
|
|
1416
|
+
const attributeDoc = attributesLine === null ? [] : [`${attributePrefix}${dim(attributesLine)}`];
|
|
1378
1417
|
const childDocs = children.map(
|
|
1379
1418
|
(child, i) => renderGraphNode(graph, child.index, childPrefix, i === children.length - 1, false)
|
|
1380
1419
|
);
|
|
1381
|
-
return [line, ...childDocs.filter((doc) => doc.length > 0)].join("\n");
|
|
1420
|
+
return [line, ...attributeDoc, ...childDocs.filter((doc) => doc.length > 0)].join("\n");
|
|
1382
1421
|
};
|
|
1383
1422
|
var renderSpanGraph = (graph) => {
|
|
1384
1423
|
const roots = [];
|
|
@@ -1393,13 +1432,133 @@ var renderSpanGraph = (graph) => {
|
|
|
1393
1432
|
return rootDocs.filter((doc) => doc.length > 0).join("\n");
|
|
1394
1433
|
};
|
|
1395
1434
|
|
|
1396
|
-
// src/cli/
|
|
1397
|
-
var
|
|
1435
|
+
// src/cli/span.ts
|
|
1436
|
+
var attributesToObject = (attributes) => Object.fromEntries(attributes);
|
|
1437
|
+
var command3 = Command6.make(
|
|
1438
|
+
"span",
|
|
1439
|
+
{
|
|
1440
|
+
data: dataOption,
|
|
1441
|
+
json: jsonOption,
|
|
1442
|
+
traceId: Argument3.string("trace-id").pipe(
|
|
1443
|
+
Argument3.withDescription("The trace ID containing the span")
|
|
1444
|
+
),
|
|
1445
|
+
spanId: Argument3.string("span-id").pipe(
|
|
1446
|
+
Argument3.withDescription("The span ID to display")
|
|
1447
|
+
)
|
|
1448
|
+
},
|
|
1449
|
+
({ data, json, spanId, traceId }) => Effect10.gen(function* () {
|
|
1450
|
+
const storage = yield* Storage;
|
|
1451
|
+
const spans = yield* storage.getSpans({ spanId, traceId });
|
|
1452
|
+
const span = spans[0];
|
|
1453
|
+
if (span === void 0) {
|
|
1454
|
+
yield* Console2.log(`No span found for trace: ${traceId}, span: ${spanId}`);
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
const events = yield* storage.getSpanEvents({ traceId, spanId });
|
|
1458
|
+
const links = yield* storage.getSpanLinks({ traceId, spanId });
|
|
1459
|
+
const startTime = getStartTime(span);
|
|
1460
|
+
const endTime = getEndTime(span);
|
|
1461
|
+
const durationNanos = endTime !== null ? endTime - startTime : null;
|
|
1462
|
+
if (json) {
|
|
1463
|
+
const output = {
|
|
1464
|
+
span: {
|
|
1465
|
+
spanId: getSpanId(span),
|
|
1466
|
+
traceId: getTraceId(span),
|
|
1467
|
+
parentSpanId: getParentSpanId(span),
|
|
1468
|
+
name: getSpanName(span),
|
|
1469
|
+
kind: getSpanKind(span),
|
|
1470
|
+
statusCode: getStatusCode(span),
|
|
1471
|
+
statusMessage: getStatusMessage(span),
|
|
1472
|
+
startTime: formatTimestamp(startTime),
|
|
1473
|
+
endTime: endTime !== null ? formatTimestamp(endTime) : null,
|
|
1474
|
+
durationMs: durationNanos !== null ? Number(durationNanos / 1000000n) : null,
|
|
1475
|
+
attributes: getAttributes(span),
|
|
1476
|
+
isExternal: isExternalSpan(span)
|
|
1477
|
+
},
|
|
1478
|
+
events: events.map((event) => ({
|
|
1479
|
+
name: event.name,
|
|
1480
|
+
time: formatTimestamp(event.time),
|
|
1481
|
+
attributes: attributesToObject(event.attributes)
|
|
1482
|
+
})),
|
|
1483
|
+
links: links.map((link) => ({
|
|
1484
|
+
linkedSpanId: link.linkedSpanId,
|
|
1485
|
+
linkedTraceId: link.linkedTraceId,
|
|
1486
|
+
attributes: attributesToObject(link.attributes)
|
|
1487
|
+
}))
|
|
1488
|
+
};
|
|
1489
|
+
yield* Console2.log(JSON.stringify(output, null, 2));
|
|
1490
|
+
} else {
|
|
1491
|
+
const fields = [
|
|
1492
|
+
field("Span", getSpanId(span)),
|
|
1493
|
+
field("Name", getSpanName(span)),
|
|
1494
|
+
field("Trace", getTraceId(span)),
|
|
1495
|
+
field("Kind", String(getSpanKind(span))),
|
|
1496
|
+
field("Status", formatStatusDoc(getStatusCode(span))),
|
|
1497
|
+
field("Started", formatTimestamp(startTime)),
|
|
1498
|
+
field("Duration", durationNanos !== null ? formatDuration(durationNanos) : "running")
|
|
1499
|
+
];
|
|
1500
|
+
const parentSpanId = getParentSpanId(span);
|
|
1501
|
+
if (parentSpanId !== null) {
|
|
1502
|
+
fields.push(field("Parent", parentSpanId));
|
|
1503
|
+
}
|
|
1504
|
+
if (endTime !== null) {
|
|
1505
|
+
fields.push(field("Ended", formatTimestamp(endTime)));
|
|
1506
|
+
}
|
|
1507
|
+
const statusMessage = getStatusMessage(span);
|
|
1508
|
+
if (statusMessage !== null) {
|
|
1509
|
+
fields.push(field("Status Message", statusMessage));
|
|
1510
|
+
}
|
|
1511
|
+
const attrs = getAttributes(span);
|
|
1512
|
+
if (Object.keys(attrs).length > 0) {
|
|
1513
|
+
fields.push(field("Attrs", JSON.stringify(attrs)));
|
|
1514
|
+
}
|
|
1515
|
+
const eventDocs = events.length === 0 ? ["Events: none"] : [
|
|
1516
|
+
`Events (${events.length}):`,
|
|
1517
|
+
...events.map((event) => {
|
|
1518
|
+
const attrs2 = attributesToObject(event.attributes);
|
|
1519
|
+
const lines = [` ${event.name} @ ${formatTimestamp(event.time)}`];
|
|
1520
|
+
if (Object.keys(attrs2).length > 0) {
|
|
1521
|
+
lines.push(` ${field("Attrs", JSON.stringify(attrs2))}`);
|
|
1522
|
+
}
|
|
1523
|
+
return lines.join("\n");
|
|
1524
|
+
})
|
|
1525
|
+
];
|
|
1526
|
+
const linkDocs = links.length === 0 ? ["Links: none"] : [
|
|
1527
|
+
`Links (${links.length}):`,
|
|
1528
|
+
...links.map((link) => {
|
|
1529
|
+
const attrs2 = attributesToObject(link.attributes);
|
|
1530
|
+
const lines = [` ${link.linkedTraceId}/${link.linkedSpanId}`];
|
|
1531
|
+
if (Object.keys(attrs2).length > 0) {
|
|
1532
|
+
lines.push(` ${field("Attrs", JSON.stringify(attrs2))}`);
|
|
1533
|
+
}
|
|
1534
|
+
return lines.join("\n");
|
|
1535
|
+
})
|
|
1536
|
+
];
|
|
1537
|
+
yield* Console2.log(renderDoc([...fields, "", ...eventDocs, "", ...linkDocs].join("\n")));
|
|
1538
|
+
}
|
|
1539
|
+
}).pipe(
|
|
1540
|
+
Effect10.scoped,
|
|
1541
|
+
Effect10.provide(makeReadOnlyLayer(data))
|
|
1542
|
+
)
|
|
1543
|
+
).pipe(
|
|
1544
|
+
Command6.withDescription("Show detailed span information"),
|
|
1545
|
+
Command6.withExamples([
|
|
1546
|
+
{
|
|
1547
|
+
command: "inspeffct span <trace-id> <span-id>",
|
|
1548
|
+
description: "Show span details with events and links"
|
|
1549
|
+
},
|
|
1550
|
+
{
|
|
1551
|
+
command: "inspeffct span --json <trace-id> <span-id>",
|
|
1552
|
+
description: "Print span details as JSON"
|
|
1553
|
+
}
|
|
1554
|
+
])
|
|
1555
|
+
);
|
|
1556
|
+
var command4 = Command6.make(
|
|
1398
1557
|
"spans",
|
|
1399
1558
|
{
|
|
1400
1559
|
data: dataOption,
|
|
1401
|
-
|
|
1402
|
-
Flag3.withDescription("Filter by
|
|
1560
|
+
runId: Flag3.string("run-id").pipe(
|
|
1561
|
+
Flag3.withDescription("Filter by run ID"),
|
|
1403
1562
|
Flag3.optional
|
|
1404
1563
|
),
|
|
1405
1564
|
json: jsonOption,
|
|
@@ -1412,17 +1571,21 @@ var command3 = Command5.make(
|
|
|
1412
1571
|
Flag3.withDescription("Filter by span name (use % for wildcards)"),
|
|
1413
1572
|
Flag3.optional
|
|
1414
1573
|
),
|
|
1574
|
+
spanId: Flag3.string("span-id").pipe(
|
|
1575
|
+
Flag3.withDescription("Filter by span ID"),
|
|
1576
|
+
Flag3.optional
|
|
1577
|
+
),
|
|
1415
1578
|
status: Flag3.string("status").pipe(
|
|
1416
1579
|
Flag3.withDescription("Filter by status: ok, error, unset"),
|
|
1417
1580
|
Flag3.optional
|
|
1418
1581
|
),
|
|
1419
|
-
trace: Flag3.string("trace").pipe(
|
|
1582
|
+
trace: Flag3.string("trace-id").pipe(
|
|
1420
1583
|
Flag3.withAlias("t"),
|
|
1421
1584
|
Flag3.withDescription("Filter by trace ID"),
|
|
1422
1585
|
Flag3.optional
|
|
1423
1586
|
)
|
|
1424
1587
|
},
|
|
1425
|
-
({ data,
|
|
1588
|
+
({ data, json, limit, minDuration, name, runId, spanId, status, trace }) => Effect10.gen(function* () {
|
|
1426
1589
|
const storage = yield* Storage;
|
|
1427
1590
|
let statusCode;
|
|
1428
1591
|
if (Option3.isSome(status)) {
|
|
@@ -1441,7 +1604,8 @@ var command3 = Command5.make(
|
|
|
1441
1604
|
}
|
|
1442
1605
|
}
|
|
1443
1606
|
const filters = {
|
|
1444
|
-
...Option3.isSome(
|
|
1607
|
+
...Option3.isSome(runId) ? { runId: runId.value } : {},
|
|
1608
|
+
...Option3.isSome(spanId) ? { spanId: spanId.value } : {},
|
|
1445
1609
|
...Option3.isSome(trace) ? { traceId: trace.value } : {},
|
|
1446
1610
|
...Option3.isSome(name) ? { name: name.value } : {},
|
|
1447
1611
|
...statusCode !== void 0 ? { status: statusCode } : {},
|
|
@@ -1508,14 +1672,30 @@ var command3 = Command5.make(
|
|
|
1508
1672
|
Effect10.scoped,
|
|
1509
1673
|
Effect10.provide(makeReadOnlyLayer(data))
|
|
1510
1674
|
)
|
|
1511
|
-
).pipe(
|
|
1512
|
-
|
|
1675
|
+
).pipe(
|
|
1676
|
+
Command6.withDescription("List spans with optional filters (from multiple traces)"),
|
|
1677
|
+
Command6.withExamples([
|
|
1678
|
+
{
|
|
1679
|
+
command: "inspeffct spans --trace-id <trace-id>",
|
|
1680
|
+
description: "List spans for a trace"
|
|
1681
|
+
},
|
|
1682
|
+
{
|
|
1683
|
+
command: "inspeffct spans --run-id <run-id>",
|
|
1684
|
+
description: "List spans captured during a specific run"
|
|
1685
|
+
},
|
|
1686
|
+
{
|
|
1687
|
+
command: "inspeffct spans --span-id <span-id>",
|
|
1688
|
+
description: "Find a span directly by ID"
|
|
1689
|
+
}
|
|
1690
|
+
])
|
|
1691
|
+
);
|
|
1692
|
+
var command5 = Command6.make(
|
|
1513
1693
|
"trace",
|
|
1514
1694
|
{
|
|
1515
1695
|
data: dataOption,
|
|
1516
1696
|
json: jsonOption,
|
|
1517
|
-
traceId:
|
|
1518
|
-
|
|
1697
|
+
traceId: Argument3.string("trace-id").pipe(
|
|
1698
|
+
Argument3.withDescription("The trace ID to display")
|
|
1519
1699
|
)
|
|
1520
1700
|
},
|
|
1521
1701
|
({ data, json, traceId }) => Effect10.gen(function* () {
|
|
@@ -1578,14 +1758,26 @@ var command4 = Command5.make(
|
|
|
1578
1758
|
Effect10.scoped,
|
|
1579
1759
|
Effect10.provide(makeReadOnlyLayer(data))
|
|
1580
1760
|
)
|
|
1581
|
-
).pipe(
|
|
1582
|
-
|
|
1761
|
+
).pipe(
|
|
1762
|
+
Command6.withDescription("Show a trace as a tree view with its spans as well"),
|
|
1763
|
+
Command6.withExamples([
|
|
1764
|
+
{
|
|
1765
|
+
command: "inspeffct trace <trace-id>",
|
|
1766
|
+
description: "Show a trace tree"
|
|
1767
|
+
},
|
|
1768
|
+
{
|
|
1769
|
+
command: "inspeffct trace --json <trace-id>",
|
|
1770
|
+
description: "Print the trace tree as JSON"
|
|
1771
|
+
}
|
|
1772
|
+
])
|
|
1773
|
+
);
|
|
1774
|
+
var command6 = Command6.make(
|
|
1583
1775
|
"traces",
|
|
1584
1776
|
{
|
|
1585
1777
|
data: dataOption,
|
|
1586
1778
|
json: jsonOption,
|
|
1587
|
-
|
|
1588
|
-
Flag3.withDescription("Filter by
|
|
1779
|
+
runId: Flag3.string("run-id").pipe(
|
|
1780
|
+
Flag3.withDescription("Filter by run ID"),
|
|
1589
1781
|
Flag3.optional
|
|
1590
1782
|
),
|
|
1591
1783
|
limit: limitOption,
|
|
@@ -1598,7 +1790,7 @@ var command5 = Command5.make(
|
|
|
1598
1790
|
Flag3.optional
|
|
1599
1791
|
)
|
|
1600
1792
|
},
|
|
1601
|
-
({ data,
|
|
1793
|
+
({ data, json, limit, runId, since, status }) => Effect10.gen(function* () {
|
|
1602
1794
|
const storage = yield* Storage;
|
|
1603
1795
|
let statusCode;
|
|
1604
1796
|
if (Option3.isSome(status)) {
|
|
@@ -1623,7 +1815,7 @@ var command5 = Command5.make(
|
|
|
1623
1815
|
sinceNanos = nowNanos - durationNanos;
|
|
1624
1816
|
}
|
|
1625
1817
|
const filters = {
|
|
1626
|
-
...Option3.isSome(
|
|
1818
|
+
...Option3.isSome(runId) ? { runId: runId.value } : {},
|
|
1627
1819
|
...statusCode !== void 0 ? { status: statusCode } : {},
|
|
1628
1820
|
...sinceNanos !== void 0 ? { since: sinceNanos } : {},
|
|
1629
1821
|
...Option3.isSome(limit) ? { limit: limit.value } : {}
|
|
@@ -1667,14 +1859,35 @@ var command5 = Command5.make(
|
|
|
1667
1859
|
Effect10.scoped,
|
|
1668
1860
|
Effect10.provide(makeReadOnlyLayer(data))
|
|
1669
1861
|
)
|
|
1670
|
-
).pipe(
|
|
1862
|
+
).pipe(
|
|
1863
|
+
Command6.withDescription("List traces with optional filters"),
|
|
1864
|
+
Command6.withExamples([
|
|
1865
|
+
{
|
|
1866
|
+
command: "inspeffct traces",
|
|
1867
|
+
description: "List recent traces"
|
|
1868
|
+
},
|
|
1869
|
+
{
|
|
1870
|
+
command: "inspeffct traces --run-id <run-id>",
|
|
1871
|
+
description: "List traces captured during a specific run"
|
|
1872
|
+
},
|
|
1873
|
+
{
|
|
1874
|
+
command: "inspeffct traces --status error --since 1h",
|
|
1875
|
+
description: "List recent traces that contain errors"
|
|
1876
|
+
}
|
|
1877
|
+
])
|
|
1878
|
+
);
|
|
1671
1879
|
|
|
1672
1880
|
// src/cli.ts
|
|
1673
|
-
var
|
|
1674
|
-
|
|
1675
|
-
|
|
1881
|
+
var command7 = Command6.make("inspeffct").pipe(
|
|
1882
|
+
Command6.withDescription(
|
|
1883
|
+
"Run your Effect application with `npx inspeffct run ...` to start capturing data, and then inspect data with the CLI."
|
|
1884
|
+
),
|
|
1885
|
+
Command6.withSubcommands([
|
|
1886
|
+
{ group: "Capture", commands: [command2, command] },
|
|
1887
|
+
{ group: "Inspect", commands: [command6, command5, command4, command3] }
|
|
1888
|
+
])
|
|
1676
1889
|
);
|
|
1677
|
-
var cli =
|
|
1890
|
+
var cli = Command6.runWith(command7, {
|
|
1678
1891
|
version: "0.0.1"
|
|
1679
1892
|
});
|
|
1680
1893
|
var encodeRunSeparator = (args) => {
|