Skip to content

Commit 529fd44

Browse files
Merge pull request #650 from simstudioai/improvement/logging-ui
improvement(logging-ui): improve logging UI to be less of information dump
2 parents 50595c5 + 717b4dd commit 529fd44

File tree

9 files changed

+286
-334
lines changed

9 files changed

+286
-334
lines changed

apps/sim/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas.tsx

Lines changed: 234 additions & 98 deletions
Large diffs are not rendered by default.

apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -494,43 +494,6 @@ export function Sidebar({
494494
</div>
495495
)}
496496

497-
{/* Enhanced Stats - only show for enhanced logs */}
498-
{log.metadata?.enhanced && log.metadata?.blockStats && (
499-
<div>
500-
<h3 className='mb-1 font-medium text-muted-foreground text-xs'>
501-
Block Execution Stats
502-
</h3>
503-
<div className='space-y-1 text-sm'>
504-
<div className='flex justify-between'>
505-
<span>Total Blocks:</span>
506-
<span className='font-medium'>{log.metadata.blockStats.total}</span>
507-
</div>
508-
<div className='flex justify-between'>
509-
<span>Successful:</span>
510-
<span className='font-medium text-green-600'>
511-
{log.metadata.blockStats.success}
512-
</span>
513-
</div>
514-
{log.metadata.blockStats.error > 0 && (
515-
<div className='flex justify-between'>
516-
<span>Failed:</span>
517-
<span className='font-medium text-red-600'>
518-
{log.metadata.blockStats.error}
519-
</span>
520-
</div>
521-
)}
522-
{log.metadata.blockStats.skipped > 0 && (
523-
<div className='flex justify-between'>
524-
<span>Skipped:</span>
525-
<span className='font-medium text-yellow-600'>
526-
{log.metadata.blockStats.skipped}
527-
</span>
528-
</div>
529-
)}
530-
</div>
531-
</div>
532-
)}
533-
534497
{/* Enhanced Cost - only show for enhanced logs with actual cost data */}
535498
{log.metadata?.enhanced && hasCostInfo && (
536499
<div>
@@ -583,7 +546,7 @@ export function Sidebar({
583546
className='w-full justify-start gap-2'
584547
>
585548
<Eye className='h-4 w-4' />
586-
View Frozen Canvas
549+
View Snapshot
587550
</Button>
588551
<p className='mt-1 text-muted-foreground text-xs'>
589552
See the exact workflow state and block inputs/outputs at execution time

apps/sim/app/workspace/[workspaceId]/logs/components/trace-spans/trace-spans-display.tsx

Lines changed: 10 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
'use client'
22

3-
import { useMemo, useState } from 'react'
4-
import {
5-
ChevronDown,
6-
ChevronDownSquare,
7-
ChevronRight,
8-
ChevronUpSquare,
9-
Code,
10-
Cpu,
11-
ExternalLink,
12-
} from 'lucide-react'
3+
import { useState } from 'react'
4+
import { ChevronDown, ChevronRight, Code, Cpu, ExternalLink } from 'lucide-react'
135
import {
146
AgentIcon,
157
ApiIcon,
@@ -203,40 +195,11 @@ export function TraceSpansDisplay({
203195
// Keep track of expanded spans
204196
const [expandedSpans, setExpandedSpans] = useState<Set<string>>(new Set())
205197

206-
// Function to collect all span IDs recursively (for expand all functionality)
207-
const collectAllSpanIds = (spans: TraceSpan[]): string[] => {
208-
const ids: string[] = []
209-
210-
const collectIds = (span: TraceSpan) => {
211-
const spanId = span.id || `span-${span.name}-${span.startTime}`
212-
ids.push(spanId)
213-
214-
// Process children
215-
if (span.children && span.children.length > 0) {
216-
span.children.forEach(collectIds)
217-
}
218-
}
219-
220-
spans.forEach(collectIds)
221-
return ids
222-
}
223-
224-
const allSpanIds = useMemo(() => {
225-
if (!traceSpans || traceSpans.length === 0) return []
226-
return collectAllSpanIds(traceSpans)
227-
}, [traceSpans])
228-
229198
// Early return after all hooks
230199
if (!traceSpans || traceSpans.length === 0) {
231200
return <div className='text-muted-foreground text-sm'>No trace data available</div>
232201
}
233202

234-
// Format total duration for better readability
235-
const _formatTotalDuration = (ms: number) => {
236-
if (ms < 1000) return `${ms}ms`
237-
return `${(ms / 1000).toFixed(2)}s (${ms}ms)`
238-
}
239-
240203
// Find the earliest start time among all spans to be the workflow start time
241204
const workflowStartTime = traceSpans.reduce((earliest, span) => {
242205
const startTime = new Date(span.startTime).getTime()
@@ -269,48 +232,10 @@ export function TraceSpansDisplay({
269232
}
270233
}
271234

272-
// Handle expand all / collapse all
273-
const handleExpandAll = () => {
274-
const newExpandedSpans = new Set(allSpanIds)
275-
setExpandedSpans(newExpandedSpans)
276-
277-
if (onExpansionChange) {
278-
onExpansionChange(true)
279-
}
280-
}
281-
282-
const handleCollapseAll = () => {
283-
setExpandedSpans(new Set())
284-
285-
if (onExpansionChange) {
286-
onExpansionChange(false)
287-
}
288-
}
289-
290-
// Determine if all spans are currently expanded
291-
const allExpanded = allSpanIds.length > 0 && allSpanIds.every((id) => expandedSpans.has(id))
292-
293235
return (
294236
<div className='w-full'>
295237
<div className='mb-2 flex items-center justify-between'>
296-
<div className='font-medium text-muted-foreground text-xs'>Trace Spans</div>
297-
<button
298-
onClick={allExpanded ? handleCollapseAll : handleExpandAll}
299-
className='flex items-center gap-1 text-muted-foreground text-xs transition-colors hover:text-foreground'
300-
title={allExpanded ? 'Collapse all spans' : 'Expand all spans'}
301-
>
302-
{allExpanded ? (
303-
<>
304-
<ChevronUpSquare className='h-3.5 w-3.5' />
305-
<span>Collapse</span>
306-
</>
307-
) : (
308-
<>
309-
<ChevronDownSquare className='h-3.5 w-3.5' />
310-
<span>Expand</span>
311-
</>
312-
)}
313-
</button>
238+
<div className='font-medium text-muted-foreground text-xs'>Workflow Execution</div>
314239
</div>
315240
<div className='w-full overflow-hidden rounded-md border shadow-sm'>
316241
{traceSpans.map((span, index) => {
@@ -369,7 +294,8 @@ function TraceSpanItem({
369294
const expanded = expandedSpans.has(spanId)
370295
const hasChildren = span.children && span.children.length > 0
371296
const hasToolCalls = span.toolCalls && span.toolCalls.length > 0
372-
const hasNestedItems = hasChildren || hasToolCalls
297+
const hasInputOutput = Boolean(span.input || span.output)
298+
const hasNestedItems = hasChildren || hasToolCalls || hasInputOutput
373299

374300
// Calculate timing information
375301
const spanStartTime = new Date(span.startTime).getTime()
@@ -389,9 +315,6 @@ function TraceSpanItem({
389315
const safeStartPercent = Math.min(100, Math.max(0, relativeStartPercent))
390316
const safeWidthPercent = Math.max(2, Math.min(100 - safeStartPercent, actualDurationPercent))
391317

392-
// For parent-relative timing display
393-
const _startOffsetPercentage = totalDuration > 0 ? (startOffset / totalDuration) * 100 : 0
394-
395318
// Handle click to expand/collapse this span
396319
const handleSpanClick = () => {
397320
if (hasNestedItems) {
@@ -605,17 +528,17 @@ function TraceSpanItem({
605528
</div>
606529
</div>
607530

608-
{/* Children and tool calls */}
531+
{/* Expanded content */}
609532
{expanded && (
610533
<div>
611534
{/* Block Input/Output Data */}
612535
{(span.input || span.output) && (
613-
<div className='mt-2 ml-8 space-y-3 overflow-hidden'>
536+
<div className='mt-2 mr-4 mb-4 ml-8 space-y-3 overflow-hidden'>
614537
{/* Input Data */}
615538
{span.input && (
616539
<div>
617540
<h4 className='mb-2 font-medium text-muted-foreground text-xs'>Input</h4>
618-
<div className='overflow-hidden rounded-md bg-secondary/30 p-3'>
541+
<div className='mb-2 overflow-hidden rounded-md bg-secondary/30 p-3'>
619542
<BlockDataDisplay data={span.input} blockType={span.type} isInput={true} />
620543
</div>
621544
</div>
@@ -627,7 +550,7 @@ function TraceSpanItem({
627550
<h4 className='mb-2 font-medium text-muted-foreground text-xs'>
628551
{span.status === 'error' ? 'Error Details' : 'Output'}
629552
</h4>
630-
<div className='overflow-hidden rounded-md bg-secondary/30 p-3'>
553+
<div className='mb-2 overflow-hidden rounded-md bg-secondary/30 p-3'>
631554
<BlockDataDisplay
632555
data={span.output}
633556
blockType={span.type}
@@ -639,12 +562,8 @@ function TraceSpanItem({
639562
)}
640563
</div>
641564
)}
642-
</div>
643-
)}
644565

645-
{/* Children and tool calls */}
646-
{expanded && (
647-
<div>
566+
{/* Children and tool calls */}
648567
{/* Render child spans */}
649568
{hasChildren && (
650569
<div>

apps/sim/app/workspace/[workspaceId]/logs/logs.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -308,14 +308,20 @@ export default function Logs() {
308308
{/* Table with fixed layout */}
309309
<div className='w-full min-w-[800px]'>
310310
{/* Header */}
311-
<div className='border-border/50 border-b'>
312-
<div className='grid grid-cols-[160px_100px_1fr_120px_100px_100px] gap-4 px-4 py-3 font-medium text-muted-foreground text-xs'>
313-
<div>Time</div>
314-
<div>Status</div>
315-
<div>Workflow</div>
316-
<div className='hidden lg:block'>Trigger</div>
317-
<div className='hidden xl:block'>Cost</div>
318-
<div>Duration</div>
311+
<div className='px-4 py-4'>
312+
<div className='rounded-lg border border-border/30 bg-muted/30'>
313+
<div className='grid grid-cols-[160px_100px_1fr_120px_100px_100px] gap-4 px-4 py-3'>
314+
<div className='font-medium text-muted-foreground text-xs'>Time</div>
315+
<div className='font-medium text-muted-foreground text-xs'>Status</div>
316+
<div className='font-medium text-muted-foreground text-xs'>Workflow</div>
317+
<div className='hidden font-medium text-muted-foreground text-xs lg:block'>
318+
Trigger
319+
</div>
320+
<div className='hidden font-medium text-muted-foreground text-xs xl:block'>
321+
Cost
322+
</div>
323+
<div className='font-medium text-muted-foreground text-xs'>Duration</div>
324+
</div>
319325
</div>
320326
</div>
321327
</div>
@@ -344,7 +350,7 @@ export default function Logs() {
344350
</div>
345351
</div>
346352
) : (
347-
<div className='space-y-1 p-4'>
353+
<div className='space-y-1 px-4 pb-4'>
348354
{logs.map((log) => {
349355
const formattedDate = formatDate(log.createdAt)
350356
const isSelected = selectedLog?.id === log.id
@@ -360,7 +366,7 @@ export default function Logs() {
360366
}`}
361367
onClick={() => handleLogClick(log)}
362368
>
363-
<div className='grid grid-cols-[160px_100px_1fr_120px_100px_100px] gap-4 p-4'>
369+
<div className='grid grid-cols-[160px_100px_1fr_120px_100px_100px] gap-4 px-4 py-4'>
364370
{/* Time */}
365371
<div>
366372
<div className='font-medium text-sm'>{formattedDate.formatted}</div>
@@ -403,13 +409,11 @@ export default function Logs() {
403409

404410
{/* Cost */}
405411
<div className='hidden xl:block'>
406-
<div className='text-xs'>
412+
<div className='text-muted-foreground text-xs'>
407413
{log.metadata?.enhanced && log.metadata?.cost?.total ? (
408-
<span className='text-muted-foreground'>
409-
${log.metadata.cost.total.toFixed(4)}
410-
</span>
414+
<span>${log.metadata.cost.total.toFixed(4)}</span>
411415
) : (
412-
<span className='text-muted-foreground'></span>
416+
<span className='pl-0.5'></span>
413417
)}
414418
</div>
415419
</div>

apps/sim/app/workspace/[workspaceId]/logs/stores/types.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,7 @@ export interface WorkflowLog {
8484
cost?: CostMetadata
8585
blockInput?: Record<string, any>
8686
enhanced?: boolean
87-
blockStats?: {
88-
total: number
89-
success: number
90-
error: number
91-
skipped: number
92-
}
87+
9388
blockExecutions?: Array<{
9489
id: string
9590
blockId: string

apps/sim/lib/logs/enhanced-execution-logger.ts

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,6 @@ export class EnhancedExecutionLogger implements IExecutionLoggerService {
194194
executionId: string
195195
endedAt: string
196196
totalDurationMs: number
197-
blockStats: {
198-
total: number
199-
success: number
200-
error: number
201-
skipped: number
202-
}
203197
costSummary: {
204198
totalCost: number
205199
totalInputCost: number
@@ -220,23 +214,24 @@ export class EnhancedExecutionLogger implements IExecutionLoggerService {
220214
finalOutput: BlockOutputData
221215
traceSpans?: TraceSpan[]
222216
}): Promise<WorkflowExecutionLog> {
223-
const {
224-
executionId,
225-
endedAt,
226-
totalDurationMs,
227-
blockStats,
228-
costSummary,
229-
finalOutput,
230-
traceSpans,
231-
} = params
217+
const { executionId, endedAt, totalDurationMs, costSummary, finalOutput, traceSpans } = params
232218

233219
logger.debug(`Completing workflow execution ${executionId}`)
234220

235-
const level = blockStats.error > 0 ? 'error' : 'info'
236-
const message =
237-
blockStats.error > 0
238-
? `Workflow execution failed: ${blockStats.error} error(s), ${blockStats.success} success(es)`
239-
: `Workflow execution completed: ${blockStats.success} block(s) executed successfully`
221+
// Determine if workflow failed by checking trace spans for errors
222+
const hasErrors = traceSpans?.some((span: any) => {
223+
const checkSpanForErrors = (s: any): boolean => {
224+
if (s.status === 'error') return true
225+
if (s.children && Array.isArray(s.children)) {
226+
return s.children.some(checkSpanForErrors)
227+
}
228+
return false
229+
}
230+
return checkSpanForErrors(span)
231+
})
232+
233+
const level = hasErrors ? 'error' : 'info'
234+
const message = hasErrors ? 'Workflow execution failed' : 'Workflow execution completed'
240235

241236
const [updatedLog] = await db
242237
.update(workflowExecutionLogs)
@@ -245,10 +240,10 @@ export class EnhancedExecutionLogger implements IExecutionLoggerService {
245240
message,
246241
endedAt: new Date(endedAt),
247242
totalDurationMs,
248-
blockCount: blockStats.total,
249-
successCount: blockStats.success,
250-
errorCount: blockStats.error,
251-
skippedCount: blockStats.skipped,
243+
blockCount: 0,
244+
successCount: 0,
245+
errorCount: 0,
246+
skippedCount: 0,
252247
totalCost: costSummary.totalCost.toString(),
253248
totalInputCost: costSummary.totalInputCost.toString(),
254249
totalOutputCost: costSummary.totalOutputCost.toString(),

0 commit comments

Comments
 (0)