Skip to main content

Logger service

The Logger service (src/services/logger.ts) is the primary debugging tool in Masterselects. It is available as window.Logger in the browser console at any time. Default log level: WARN — only warnings and errors are shown by default.

Usage in code

import { Logger } from '@/services/logger';

const log = Logger.create('ModuleName');

log.debug('message', { data });  // shown only when module enabled + level <= DEBUG
log.info('message');             // shown when level <= INFO
log.warn('message', data);       // shown always (orange); always buffered
log.error('message', error);     // shown always (red); always buffered; captures stack trace

Timing helper

const log = Logger.create('Export');

const done = log.time('Encoding video');
// ... do work ...
done();
// Output: [Export] Encoding video completed in 1234.56ms

Grouped logs

const log = Logger.create('Compositor');

log.group('Rendering frame 42', () => {
  log.debug('Collecting layers');
  log.debug('Applying effects');
  log.debug('Compositing');
});

Console commands

All commands are available as Logger.<method>() or window.Logger.<method>() in the browser console.

Enable/disable debug logs

Logger.enable('WebGPU,FFmpeg')   // enable specific modules (substring match, case-insensitive)
Logger.enable('*')               // enable all modules
Logger.disable()                 // disable debug logs (errors still shown)

Set log level

Logger.setLevel('DEBUG')   // show all logs
Logger.setLevel('INFO')    // show INFO and above
Logger.setLevel('WARN')    // show only warnings and errors (default)
Logger.setLevel('ERROR')   // show only errors

Inspect logs

Logger.search('device')    // search by keyword (message, module, data)
Logger.errors()            // get only buffered errors
Logger.dump(50)            // pretty-print last 50 entries
Logger.summary()           // { totalLogs, errorCount, warnCount, recentErrors, activeModules }
Logger.export()            // full JSON export of config + all buffered logs
Logger.getBuffer()         // all buffered log entries
Logger.getBuffer('WARN')   // filtered by level

Status and configuration

Logger.status()            // print current configuration table
Logger.modules()           // list all registered module names
Logger.clear()             // clear the log buffer
Logger.setTimestamps(false) // toggle timestamp prefixes

Log sync (dev mode)

In development, logs are automatically synced to the Vite dev server every 2 seconds via POST /api/logs.
LogSync.status()   // 'running' or 'stopped'
LogSync.stop()
LogSync.start()

Common module groups

// GPU/Rendering
Logger.enable('WebGPU,Compositor,RenderLoop,TextureManager')

// Export pipeline
Logger.enable('Export,FrameExporter,VideoEncoder,AudioEncoder,FFmpeg')

// Audio system
Logger.enable('Audio,AudioMixer,AudioEncoder,TimeStretch')

// Project/storage
Logger.enable('Project,ProjectCore,FileStorage')

// Timeline
Logger.enable('Timeline,Clip,Track,Keyframe')

// Playback debugging
Logger.enable('WebCodecsPlayer,PlaybackHealth,LayerCollector')
Logger.setLevel('DEBUG')

// Video sync + frame pipeline
Logger.enable('VideoSyncManager,ParallelDecode,RenderLoop')
Logger.setLevel('DEBUG')

Common issues

ProblemSolution
15 fps on LinuxEnable Vulkan: chrome://flags/#enable-vulkan
”Device mismatch” errorHMR broke the engine singleton — refresh the page
Black canvas after reloadCold-start: video GPU surface not warm. Press Play/Pause once, or wait for preCacheVideoFrame
WebCodecs failsAutomatically falls back to HTMLVideoElement
Device lostAuto-recovery up to 3 attempts, then manual page reload
Black preview / no renderingLogger.enable('WebGPU,Compositor,RenderLoop') + Logger.setLevel('DEBUG')
Export failsLogger.enable('Export,FrameExporter,VideoEncoder,FFmpeg') + Logger.setLevel('DEBUG')
Audio out of syncLogger.enable('Audio,AudioMixer,TimeStretch') + Logger.setLevel('DEBUG')
File import problemsLogger.enable('Media,Import,Project') + Logger.setLevel('DEBUG')

WebCodecs pipeline monitors

Two ring-buffer monitors are exposed on window for console-based playback debugging.

window.__WC_PIPELINE__

WebCodecs decode pipeline events (set by src/services/monitoring/wcPipelineMonitor.ts). 5000-event ring buffer. Recorded events include:
  • decode_feed, decode_output — sample feed and frame output
  • frame_read, frame_drop — frame consumption and drops
  • decoder_reset — decoder reinitialization
  • pending_seek_start/end, seek_start/end/skip/cancel/publish — seek lifecycle
  • collector_hold, collector_drop — frame collector decisions
  • drift_correct, queue_pressure, stall, rAF_gap — health metrics
  • play, pause, advance_seek — playback state changes

window.__VF_PIPELINE__

VideoFrame (HTMLVideo + VideoFrame API) pipeline events (set by src/services/monitoring/vfPipelineMonitor.ts). 5000-event ring buffer. Recorded events include:
  • vf_capture, vf_read, vf_drop — frame delivery lifecycle
  • vf_gpu_cold, vf_gpu_ready — GPU surface warmup
  • vf_play, vf_pause, vf_seek_fast, vf_seek_precise, vf_seek_done — playback and seeking
  • vf_drift, vf_stall, vf_readystate_drop — health and sync
  • audio_drift, audio_drift_correct, audio_status — audio sync

AI debug tools via bridge

When the dev server (or Native Helper) is running, the AI bridge exposes debug tools callable from any HTTP client:
ToolDescription
getStatsEngine snapshot: FPS, timing, decoder type, drops, audio, GPU memory
getStatsHistoryN snapshots over time with min/max/avg summary
getLogsFilter browser logs by level, module, or search text
getPlaybackTraceWebCodecs/VF pipeline events + health state
# Engine stats snapshot
curl -X POST http://127.0.0.1:9877/api/ai-tools \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{"tool":"getStats","args":{}}'

# Filter logs for warnings from PlaybackHealth
curl -X POST http://127.0.0.1:9877/api/ai-tools \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{"tool":"getLogs","args":{"level":"WARN","module":"PlaybackHealth"}}'

# Playback trace (last 10 seconds of events)
curl -X POST http://127.0.0.1:9877/api/ai-tools \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{"tool":"getPlaybackTrace","args":{"windowMs":10000}}'
See AI Tools Bridge for the full tool list and authentication details.

Playback monitoring services

7 monitoring services in src/services/monitoring/ provide deeper playback health data:
ServiceFileWhat it tracks
playbackHealthMonitorplaybackHealthMonitor.ts8 anomaly types: FRAME_STALL, WARMUP_STUCK, RVFC_ORPHANED, SEEK_STUCK, READYSTATE_DROP, GPU_SURFACE_COLD, RENDER_STALL, HIGH_DROP_RATE. Per-clip escalation: 3+ anomalies within 12s triggers aggressive recovery
playbackDebugStatsplaybackDebugStats.tsReal-time stats: pipeline name, decoder resets, pending seek timing, collector hold/drop counts
framePhaseMonitorframePhaseMonitor.tsFrame lifecycle phase timing: stats, build, render, sync-video, sync-audio, cache
wcPipelineMonitorwcPipelineMonitor.tsWebCodecs event ring buffer (window.__WC_PIPELINE__)
vfPipelineMonitorvfPipelineMonitor.tsVideoFrame event ring buffer (window.__VF_PIPELINE__)
scrubSettleStatescrubSettleState.tsScrub-to-play transition state per clip (settle, retry, warmup stages)

Logger configuration

Buffering behavior

  • WARN and ERROR entries are always buffered (for post-mortem debugging)
  • DEBUG and INFO entries are only buffered when they are displayed (module enabled + level threshold met)
  • Buffer is a FIFO ring of 500 entries

Persistence

Logger configuration is saved to localStorage under the key logger_config. Enabled modules, level, timestamps setting, and buffer size all persist across page refreshes.

Log entry structure

interface LogEntry {
  timestamp: string;  // ISO timestamp
  level: LogLevel;    // 'DEBUG' | 'INFO' | 'WARN' | 'ERROR'
  module: string;     // Module name
  message: string;    // Log message
  data?: unknown;     // Optional attached data
  stack?: string;     // Stack trace (errors only)
}

Build docs developers (and LLMs) love