Skip to content

Commit b0a761a

Browse files
feat(cli): expose log detail trace spans
1 parent cc75820 commit b0a761a

4 files changed

Lines changed: 109 additions & 6 deletions

File tree

packages/sim-cli/README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ sim workflows deploy|undeploy|rollback <id>
125125
sim workflows run <id> [--input <json|@file>] [--select-output <path>…]
126126

127127
sim logs list [--level error] [--workflow <id>…] [--trigger <name>…] [--start <date>]
128-
sim logs get <id>
129-
sim logs execution <executionId>
128+
sim logs get <logId>
129+
sim logs executions get <executionId>
130130

131131
sim tables ls [path] [--search <text>] [--limit <n>]
132132
sim tables list [--folder <path>]
@@ -170,6 +170,13 @@ sim billing logs [--period 7d] [--source sim-chat] [--limit <n>]
170170

171171
The `sim-chat` billing source combines Copilot and workspace chat usage.
172172

173+
`sim logs get` keeps the default human output concise. Use JSON or YAML to
174+
inspect its complete `executionData` and recursive `traceSpans` tree:
175+
176+
```bash
177+
sim logs get <logId> --output json | jq '.traceSpans'
178+
```
179+
173180
Workflow output selectors use `blockName.field` syntax, such as
174181
`--select-output agent_1.content`; fields that are not produced are omitted.
175182

packages/sim-cli/src/contract/commands.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ export const CLI_CONTRACT: CliContract = {
166166
],
167167
},
168168
getLog: {
169-
describe: 'Show a log summary (execution data is available in JSON or YAML output)',
169+
describe:
170+
'Show a log summary (traceSpans and executionData are included in JSON or YAML output)',
170171
fields: [
171172
{ header: 'id' },
172173
{ header: 'execution', path: 'executionId' },

packages/sim-cli/src/generated/v2-api.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,39 @@ export type GetLogParams = {
21752175
id: string
21762176
}
21772177

2178+
type GetLogResponseRef0 = {
2179+
id: string
2180+
name: string
2181+
type: string
2182+
duration?: number
2183+
durationMs?: number
2184+
startTime?: string
2185+
endTime?: string
2186+
status?: string
2187+
blockId?: string
2188+
input?: unknown
2189+
output?: unknown
2190+
tokens?:
2191+
| number
2192+
| {
2193+
total?: number
2194+
input?: number
2195+
output?: number
2196+
}
2197+
relativeStartMs?: number
2198+
toolCalls?: Array<{
2199+
id?: string
2200+
name?: string
2201+
arguments?: unknown
2202+
result?: unknown
2203+
error?: string
2204+
startTime?: string
2205+
endTime?: string
2206+
duration?: number
2207+
}>
2208+
children?: Array<GetLogResponseRef0>
2209+
}
2210+
21782211
export type GetLogResponse = {
21792212
data: {
21802213
id: string
@@ -2198,6 +2231,7 @@ export type GetLogResponse = {
21982231
deleted: boolean
21992232
}
22002233
executionData: unknown
2234+
traceSpans: Array<GetLogResponseRef0>
22012235
cost: {
22022236
total: number
22032237
} | null
@@ -2897,6 +2931,39 @@ export type ListLogsQuery = {
28972931
folderPaths?: string
28982932
}
28992933

2934+
type ListLogsResponseRef0 = {
2935+
id: string
2936+
name: string
2937+
type: string
2938+
duration?: number
2939+
durationMs?: number
2940+
startTime?: string
2941+
endTime?: string
2942+
status?: string
2943+
blockId?: string
2944+
input?: unknown
2945+
output?: unknown
2946+
tokens?:
2947+
| number
2948+
| {
2949+
total?: number
2950+
input?: number
2951+
output?: number
2952+
}
2953+
relativeStartMs?: number
2954+
toolCalls?: Array<{
2955+
id?: string
2956+
name?: string
2957+
arguments?: unknown
2958+
result?: unknown
2959+
error?: string
2960+
startTime?: string
2961+
endTime?: string
2962+
duration?: number
2963+
}>
2964+
children?: Array<ListLogsResponseRef0>
2965+
}
2966+
29002967
export type ListLogsResponse = {
29012968
data: Array<{
29022969
id: string
@@ -2919,7 +2986,7 @@ export type ListLogsResponse = {
29192986
deleted: boolean
29202987
}
29212988
finalOutput?: unknown
2922-
traceSpans?: unknown
2989+
traceSpans?: Array<ListLogsResponseRef0>
29232990
}>
29242991
nextCursor: string | null
29252992
}

packages/sim-cli/src/runtime/build.test.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,10 @@ describe('commands parsed through commander', () => {
458458
/--encoding.*utf-8.*base64/s
459459
)
460460
})
461+
462+
it('points log detail users to complete trace output', () => {
463+
expect(commandAt('logs', 'get').description()).toMatch(/traceSpans.*JSON or YAML/)
464+
})
461465
})
462466

463467
describe('single-resource rendering', () => {
@@ -555,7 +559,7 @@ describe('single-resource rendering', () => {
555559
expect(JSON.parse(printed[0])).toEqual({ row: { id: 'r1' }, operation: 'inserted' })
556560
})
557561

558-
it('keeps sensitive execution data out of human log output', async () => {
562+
it('keeps sensitive execution detail out of human log output', async () => {
559563
const log = {
560564
id: 'log_1',
561565
executionId: 'exec_1',
@@ -568,14 +572,38 @@ describe('single-resource rendering', () => {
568572
cost: { total: 0.001 },
569573
files: [],
570574
executionData: { env: { SECRET_TOKEN: 'encrypted-value' } },
575+
traceSpans: [
576+
{
577+
id: 'span_1',
578+
name: 'Workflow Execution',
579+
type: 'workflow',
580+
children: [
581+
{
582+
id: 'span_2',
583+
name: 'Send email',
584+
type: 'block',
585+
input: { recipient: 'private@example.com' },
586+
},
587+
],
588+
},
589+
],
571590
}
572591

573592
const human = await lines(['logs', 'get', 'log_1'], log, 'text')
574593
expect(human.join('\n')).not.toContain('executionData')
575594
expect(human.join('\n')).not.toContain('SECRET_TOKEN')
595+
expect(human.join('\n')).not.toContain('traceSpans')
596+
expect(human.join('\n')).not.toContain('private@example.com')
576597

577598
const machine = await lines(['logs', 'get', 'log_1'], log, 'json')
578-
expect(JSON.parse(machine[0])).toMatchObject({ executionData: log.executionData })
599+
expect(JSON.parse(machine[0])).toMatchObject({
600+
executionData: log.executionData,
601+
traceSpans: log.traceSpans,
602+
})
603+
604+
const yaml = await lines(['logs', 'get', 'log_1'], log, 'yaml')
605+
expect(yaml.join('\n')).toContain('traceSpans:')
606+
expect(yaml.join('\n')).toContain('span_2')
579607
})
580608
})
581609

0 commit comments

Comments
 (0)