From e102b6cf17c97298d9a6e2fd09e148d524b34d0f Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Wed, 9 Jul 2025 19:19:53 -0700 Subject: [PATCH] improve logging ui --- .../frozen-canvas/frozen-canvas.tsx | 101 ++++++++++++++---- .../logs/components/sidebar/sidebar.tsx | 39 +------ .../trace-spans/trace-spans-display.tsx | 87 ++------------- .../app/workspace/[workspaceId]/logs/logs.tsx | 28 ++--- .../[workspaceId]/logs/stores/types.ts | 7 +- .../sim/lib/logs/enhanced-execution-logger.ts | 22 ++-- apps/sim/lib/logs/enhanced-logging-factory.ts | 43 -------- apps/sim/lib/logs/enhanced-logging-session.ts | 5 - apps/sim/lib/logs/types.ts | 14 +-- 9 files changed, 116 insertions(+), 230 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas.tsx index bc2e11c0b0..76a8ea9bda 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas.tsx @@ -3,12 +3,15 @@ import { useEffect, useState } from 'react' import { AlertCircle, + ChevronDown, ChevronLeft, ChevronRight, + ChevronUp, Clock, DollarSign, Hash, Loader2, + Maximize2, X, Zap, } from 'lucide-react' @@ -21,6 +24,69 @@ import type { WorkflowState } from '@/stores/workflows/workflow/types' const logger = createLogger('FrozenCanvas') +function ExpandableDataSection({ title, data }: { title: string; data: any }) { + const [isExpanded, setIsExpanded] = useState(false) + const [isModalOpen, setIsModalOpen] = useState(false) + + const jsonString = JSON.stringify(data, null, 2) + const isLargeData = jsonString.length > 500 || jsonString.split('\n').length > 10 + + return ( + <> +
+
+

{title}

+
+ {isLargeData && ( + + )} + +
+
+
+
{jsonString}
+
+
+ + {/* Modal for large data */} + {isModalOpen && ( +
+
+
+

{title}

+ +
+
+
{jsonString}
+
+
+
+ )} + + ) +} + function formatExecutionData(executionData: any) { const { inputData, @@ -160,14 +226,14 @@ function PinnedLogs({ executionData, onClose }: { executionData: any; onClose: ( {formatted.duration} - {formatted.cost && ( + {formatted.cost && formatted.cost.total > 0 && (
${formatted.cost.total.toFixed(5)}
)} - {formatted.tokens && ( + {formatted.tokens && formatted.tokens.total > 0 && (
{formatted.tokens.total} tokens @@ -175,21 +241,17 @@ function PinnedLogs({ executionData, onClose }: { executionData: any; onClose: ( )}
-
-

Input

-
-
{JSON.stringify(formatted.input, null, 2)}
-
-
+ -
-

Output

-
-
{JSON.stringify(formatted.output, null, 2)}
-
-
+ - {formatted.cost && ( + {formatted.cost && formatted.cost.total > 0 && (

Cost Breakdown

@@ -209,7 +271,7 @@ function PinnedLogs({ executionData, onClose }: { executionData: any; onClose: (
)} - {formatted.tokens && ( + {formatted.tokens && formatted.tokens.total > 0 && (

Token Usage

@@ -242,12 +304,7 @@ interface FrozenCanvasData { startedAt: string endedAt?: string totalDurationMs?: number - blockStats: { - total: number - success: number - error: number - skipped: number - } + cost: { total: number | null input: number | null diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx index 78371d6e7f..373c4ae63e 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx @@ -494,42 +494,7 @@ export function Sidebar({
)} - {/* Enhanced Stats - only show for enhanced logs */} - {log.metadata?.enhanced && log.metadata?.blockStats && ( -
-

- Block Execution Stats -

-
-
- Total Blocks: - {log.metadata.blockStats.total} -
-
- Successful: - - {log.metadata.blockStats.success} - -
- {log.metadata.blockStats.error > 0 && ( -
- Failed: - - {log.metadata.blockStats.error} - -
- )} - {log.metadata.blockStats.skipped > 0 && ( -
- Skipped: - - {log.metadata.blockStats.skipped} - -
- )} -
-
- )} + {/* Enhanced Cost - only show for enhanced logs with actual cost data */} {log.metadata?.enhanced && hasCostInfo && ( @@ -583,7 +548,7 @@ export function Sidebar({ className='w-full justify-start gap-2' > - View Frozen Canvas + View Snapshot

See the exact workflow state and block inputs/outputs at execution time diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/trace-spans/trace-spans-display.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/trace-spans/trace-spans-display.tsx index 056372083a..5d6aea8e75 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/trace-spans/trace-spans-display.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/trace-spans/trace-spans-display.tsx @@ -1,11 +1,9 @@ 'use client' -import { useMemo, useState } from 'react' +import { useState } from 'react' import { ChevronDown, - ChevronDownSquare, ChevronRight, - ChevronUpSquare, Code, Cpu, ExternalLink, @@ -203,39 +201,16 @@ export function TraceSpansDisplay({ // Keep track of expanded spans const [expandedSpans, setExpandedSpans] = useState>(new Set()) - // Function to collect all span IDs recursively (for expand all functionality) - const collectAllSpanIds = (spans: TraceSpan[]): string[] => { - const ids: string[] = [] - const collectIds = (span: TraceSpan) => { - const spanId = span.id || `span-${span.name}-${span.startTime}` - ids.push(spanId) - // Process children - if (span.children && span.children.length > 0) { - span.children.forEach(collectIds) - } - } - spans.forEach(collectIds) - return ids - } - - const allSpanIds = useMemo(() => { - if (!traceSpans || traceSpans.length === 0) return [] - return collectAllSpanIds(traceSpans) - }, [traceSpans]) // Early return after all hooks if (!traceSpans || traceSpans.length === 0) { return

No trace data available
} - // Format total duration for better readability - const _formatTotalDuration = (ms: number) => { - if (ms < 1000) return `${ms}ms` - return `${(ms / 1000).toFixed(2)}s (${ms}ms)` - } + // Find the earliest start time among all spans to be the workflow start time const workflowStartTime = traceSpans.reduce((earliest, span) => { @@ -269,48 +244,12 @@ export function TraceSpansDisplay({ } } - // Handle expand all / collapse all - const handleExpandAll = () => { - const newExpandedSpans = new Set(allSpanIds) - setExpandedSpans(newExpandedSpans) - if (onExpansionChange) { - onExpansionChange(true) - } - } - - const handleCollapseAll = () => { - setExpandedSpans(new Set()) - - if (onExpansionChange) { - onExpansionChange(false) - } - } - - // Determine if all spans are currently expanded - const allExpanded = allSpanIds.length > 0 && allSpanIds.every((id) => expandedSpans.has(id)) return (
-
Trace Spans
- +
Workflow Execution
{traceSpans.map((span, index) => { @@ -369,7 +308,8 @@ function TraceSpanItem({ const expanded = expandedSpans.has(spanId) const hasChildren = span.children && span.children.length > 0 const hasToolCalls = span.toolCalls && span.toolCalls.length > 0 - const hasNestedItems = hasChildren || hasToolCalls + const hasInputOutput = Boolean(span.input || span.output) + const hasNestedItems = hasChildren || hasToolCalls || hasInputOutput // Calculate timing information const spanStartTime = new Date(span.startTime).getTime() @@ -389,8 +329,7 @@ function TraceSpanItem({ const safeStartPercent = Math.min(100, Math.max(0, relativeStartPercent)) const safeWidthPercent = Math.max(2, Math.min(100 - safeStartPercent, actualDurationPercent)) - // For parent-relative timing display - const _startOffsetPercentage = totalDuration > 0 ? (startOffset / totalDuration) * 100 : 0 + // Handle click to expand/collapse this span const handleSpanClick = () => { @@ -605,17 +544,17 @@ function TraceSpanItem({
- {/* Children and tool calls */} + {/* Expanded content */} {expanded && (
{/* Block Input/Output Data */} {(span.input || span.output) && ( -
+
{/* Input Data */} {span.input && (

Input

-
+
@@ -627,7 +566,7 @@ function TraceSpanItem({

{span.status === 'error' ? 'Error Details' : 'Output'}

-
+
)} -
- )} - {/* Children and tool calls */} - {expanded && ( -
+ {/* Children and tool calls */} {/* Render child spans */} {hasChildren && (
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx index 87c32eb3e3..45d628f559 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/logs.tsx @@ -308,14 +308,16 @@ export default function Logs() { {/* Table with fixed layout */}
{/* Header */} -
-
-
Time
-
Status
-
Workflow
-
Trigger
-
Cost
-
Duration
+
+
+
+
Time
+
Status
+
Workflow
+
Trigger
+
Cost
+
Duration
+
@@ -344,7 +346,7 @@ export default function Logs() {
) : ( -
+
{logs.map((log) => { const formattedDate = formatDate(log.createdAt) const isSelected = selectedLog?.id === log.id @@ -360,7 +362,7 @@ export default function Logs() { }`} onClick={() => handleLogClick(log)} > -
+
{/* Time */}
{formattedDate.formatted}
@@ -403,13 +405,13 @@ export default function Logs() { {/* Cost */}
-
+
{log.metadata?.enhanced && log.metadata?.cost?.total ? ( - + ${log.metadata.cost.total.toFixed(4)} ) : ( - — + — )}
diff --git a/apps/sim/app/workspace/[workspaceId]/logs/stores/types.ts b/apps/sim/app/workspace/[workspaceId]/logs/stores/types.ts index 0108ada3dc..54d8b632df 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/stores/types.ts +++ b/apps/sim/app/workspace/[workspaceId]/logs/stores/types.ts @@ -84,12 +84,7 @@ export interface WorkflowLog { cost?: CostMetadata blockInput?: Record enhanced?: boolean - blockStats?: { - total: number - success: number - error: number - skipped: number - } + blockExecutions?: Array<{ id: string blockId: string diff --git a/apps/sim/lib/logs/enhanced-execution-logger.ts b/apps/sim/lib/logs/enhanced-execution-logger.ts index 561e6570fa..e72350047b 100644 --- a/apps/sim/lib/logs/enhanced-execution-logger.ts +++ b/apps/sim/lib/logs/enhanced-execution-logger.ts @@ -194,12 +194,6 @@ export class EnhancedExecutionLogger implements IExecutionLoggerService { executionId: string endedAt: string totalDurationMs: number - blockStats: { - total: number - success: number - error: number - skipped: number - } costSummary: { totalCost: number totalInputCost: number @@ -224,7 +218,6 @@ export class EnhancedExecutionLogger implements IExecutionLoggerService { executionId, endedAt, totalDurationMs, - blockStats, costSummary, finalOutput, traceSpans, @@ -232,11 +225,8 @@ export class EnhancedExecutionLogger implements IExecutionLoggerService { logger.debug(`Completing workflow execution ${executionId}`) - const level = blockStats.error > 0 ? 'error' : 'info' - const message = - blockStats.error > 0 - ? `Workflow execution failed: ${blockStats.error} error(s), ${blockStats.success} success(es)` - : `Workflow execution completed: ${blockStats.success} block(s) executed successfully` + const level = 'info' + const message = `Workflow execution completed` const [updatedLog] = await db .update(workflowExecutionLogs) @@ -245,10 +235,10 @@ export class EnhancedExecutionLogger implements IExecutionLoggerService { message, endedAt: new Date(endedAt), totalDurationMs, - blockCount: blockStats.total, - successCount: blockStats.success, - errorCount: blockStats.error, - skippedCount: blockStats.skipped, + blockCount: 0, + successCount: 0, + errorCount: 0, + skippedCount: 0, totalCost: costSummary.totalCost.toString(), totalInputCost: costSummary.totalInputCost.toString(), totalOutputCost: costSummary.totalOutputCost.toString(), diff --git a/apps/sim/lib/logs/enhanced-logging-factory.ts b/apps/sim/lib/logs/enhanced-logging-factory.ts index 72cde27efd..cd9d9bffb4 100644 --- a/apps/sim/lib/logs/enhanced-logging-factory.ts +++ b/apps/sim/lib/logs/enhanced-logging-factory.ts @@ -46,50 +46,7 @@ export async function loadWorkflowStateForExecution(workflowId: string): Promise } } -export function calculateBlockStats(traceSpans: any[]): { - total: number - success: number - error: number - skipped: number -} { - if (!traceSpans || traceSpans.length === 0) { - return { total: 0, success: 0, error: 0, skipped: 0 } - } - // Recursively collect all block spans from the trace span tree - const collectBlockSpans = (spans: any[]): any[] => { - const blocks: any[] = [] - - for (const span of spans) { - // Check if this span is an actual workflow block - if ( - span.type && - span.type !== 'workflow' && - span.type !== 'provider' && - span.type !== 'model' && - span.blockId - ) { - blocks.push(span) - } - - // Recursively check children - if (span.children && Array.isArray(span.children)) { - blocks.push(...collectBlockSpans(span.children)) - } - } - - return blocks - } - - const blockSpans = collectBlockSpans(traceSpans) - - const total = blockSpans.length - const success = blockSpans.filter((span) => span.status === 'success').length - const error = blockSpans.filter((span) => span.status === 'error').length - const skipped = blockSpans.filter((span) => span.status === 'skipped').length - - return { total, success, error, skipped } -} export function calculateCostSummary(traceSpans: any[]): { totalCost: number diff --git a/apps/sim/lib/logs/enhanced-logging-session.ts b/apps/sim/lib/logs/enhanced-logging-session.ts index 7d0bc174eb..e3eed5dad9 100644 --- a/apps/sim/lib/logs/enhanced-logging-session.ts +++ b/apps/sim/lib/logs/enhanced-logging-session.ts @@ -1,7 +1,6 @@ import { createLogger } from '@/lib/logs/console-logger' import { enhancedExecutionLogger } from './enhanced-execution-logger' import { - calculateBlockStats, calculateCostSummary, createEnvironmentObject, createTriggerObject, @@ -99,14 +98,12 @@ export class EnhancedLoggingSession { const { endedAt, totalDurationMs, finalOutput, traceSpans } = params try { - const blockStats = calculateBlockStats(traceSpans || []) const costSummary = calculateCostSummary(traceSpans || []) await enhancedExecutionLogger.completeWorkflowExecution({ executionId: this.executionId, endedAt: endedAt || new Date().toISOString(), totalDurationMs: totalDurationMs || 0, - blockStats, costSummary, finalOutput: finalOutput || {}, traceSpans: traceSpans || [], @@ -126,7 +123,6 @@ export class EnhancedLoggingSession { async completeWithError(error?: any): Promise { try { - const blockStats = { total: 0, success: 0, error: 1, skipped: 0 } const costSummary = { totalCost: 0, totalInputCost: 0, @@ -141,7 +137,6 @@ export class EnhancedLoggingSession { executionId: this.executionId, endedAt: new Date().toISOString(), totalDurationMs: 0, - blockStats, costSummary, finalOutput: null, traceSpans: [], diff --git a/apps/sim/lib/logs/types.ts b/apps/sim/lib/logs/types.ts index bf1c76f22a..1bb8700130 100644 --- a/apps/sim/lib/logs/types.ts +++ b/apps/sim/lib/logs/types.ts @@ -169,12 +169,7 @@ export interface WorkflowExecutionSummary { startedAt: string endedAt: string durationMs: number - blockStats: { - total: number - success: number - error: number - skipped: number - } + costSummary: { total: number inputCost: number @@ -360,12 +355,7 @@ export interface ExecutionLoggerService { executionId: string endedAt: string totalDurationMs: number - blockStats: { - total: number - success: number - error: number - skipped: number - } + costSummary: { totalCost: number totalInputCost: number