Skip to content

feat: add log frequency visualization per container#2

Open
zhuge-liang-bot[bot] wants to merge 9 commits into
masterfrom
feat/log-frequency-visualization
Open

feat: add log frequency visualization per container#2
zhuge-liang-bot[bot] wants to merge 9 commits into
masterfrom
feat/log-frequency-visualization

Conversation

@zhuge-liang-bot

@zhuge-liang-bot zhuge-liang-bot Bot commented Mar 30, 2026

Copy link
Copy Markdown

Summary

  • Add per-container log frequency visualization (stacked bar chart: info=green, warn=orange, error=red, debug=blue)
  • Add crash-loop detection badges and "Hot" anomaly score column
  • Fix Docker multiplexed stream demux (binary header stripping for non-TTY containers)
  • Fix v-memo performance regression (object refs → primitive-only values + logStatsVersion counter)
  • Parallelize log stats collection (bounded 5-goroutine pool with context cancellation)
  • Fix reactive proxy increment no-op when Vue unwraps Ref in reactive array
  • Fix CI: allow bot actors in claude-code-review workflow

Changes

Backend (Go)

  • container_store.go: collectLogStats() parallelized with semaphore, demuxDockerStream(), atomic.Bool guard
  • events.go: SSE container-log-stat event emission, buffered channel (50)
  • Service layer wiring: SubscribeLogStats through DockerClientService → MultiHostService → SSE

Frontend (TypeScript/Vue)

  • LogFrequencyChart.vue: New stacked bar chart component with responsive downsampling
  • Container.ts: logStatsVersion counter, restartCount 1s cache, anomalyScore, statusBadge
  • ContainerTable.vue: v-memo with primitives only, Logs/Hot columns
  • container.ts (store): SSE handlers for container-log-stat and enhanced container-event

CI

  • claude-code-review.yml: Add allowed_bots: '*' for bot-initiated PRs

Commits (9)

  1. b8e5e97b feat: add log frequency visualization per container
  2. 13a2e965 fix: demux Docker multiplexed stream in collectLogStats
  3. 35959b95 feat: add crash-loop badges and hot sort column
  4. 9196594b fix: address Codex review — scanner buffer, error propagation, non-blocking subscribers
  5. b3fe9dd0 fix: prevent goroutine leak and overlapping log stat collection
  6. 4562ca93 fix: include reactive deps in v-memo to enable live UI updates
  7. 13b69021 fix: resolve v-memo performance regression
  8. bc456b80 fix: reactive proxy increment no-op and semaphore context leak
  9. 74ba36aa ci: allow bot actors in claude-code-review workflow

Test plan

  • Go tests pass (all packages)
  • TypeScript typecheck pass
  • Vite production build pass
  • SSE container-log-stat events emit non-zero data (verified on dev2)
  • UI does not freeze with 13+ containers (v-memo primitive fix)
  • Manual verification: log frequency chart renders correctly in browser

🤖 Generated with Claude Code

icedac and others added 9 commits March 30, 2026 19:44
Add a "Logs" column to the container dashboard table showing real-time
log output frequency as color-coded stacked bar charts per container.
Colors: info=green, warn=orange, error=red, debug=blue, fatal=red.

Backend: ContainerStore collects log stats every 5s by sampling recent
Docker logs and counting by level using existing level_guesser. Data
flows through SubscribeLogStats → SSE "container-log-stat" events.

Frontend: New LogFrequencyChart component renders stacked bars.
Container model tracks 60-entry log stats history with updateLogStat().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Non-TTY containers return logs with 8-byte binary headers (stream type +
length). bufio.Scanner was splitting on newlines within these binary
frames, corrupting every line. Now properly strips multiplexed headers
before scanning.

Also counts lines with unrecognized log levels as "info" instead of
silently discarding them.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Track restart count (10min window) and exit codes from container events
- Show status badges: OOM, SIGTERM, Exit N, crash-loop count, unhealthy
- Add anomaly score based on restarts, health, error rate, CPU/mem pressure
- Add sortable "Hot" column to surface containers needing attention

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ocking subscribers

- Increase bufio.Scanner buffer to 256KB for long JSON log lines
- Check scanner.Err() after scan loop to surface truncated reads
- Use pw.CloseWithError(err) to propagate demux errors to scanner
- Make subscriber send non-blocking (drop stat if slow consumer)
- Fix exit 137 label: "Killed" not "OOM" (SIGKILL != guaranteed OOM)
- Prune _restartTimestamps on every restartCount access, compute once per getter chain

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract collectLogStatForContainer for cleaner lifecycle management
- Use pw.CloseWithError(err) consistently (nil propagation is safe)
- Add atomic.Bool guard to prevent overlapping collectLogStats runs
- Buffer logStats SSE channel (50) to reduce backpressure on slow clients

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
v-memo="[container.id, statMode]" was freezing log sparklines, crash
badges, hot scores, and stat displays after initial render. Now tracks
state, stat, anomalyScore, and latest logStat so rows re-render when
data changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: adding container.stat (object, changes ~1/sec) to v-memo
triggered ~13 full row re-renders/sec, cascading into LogFrequencyChart
re-mounts (300 DOM elements × 13 containers).

Changes:
- v-memo now uses only primitives: id, statMode, state, logStatsVersion,
  anomalyScore (numbers that change every ~5s, not every ~1s)
- Container.ts: added logStatsVersion counter + restartCount 1s cache
- Go: parallelized collectLogStats with bounded 5-goroutine pool

Co-Authored-By: Zhuge <zhugehyuk@gmail.com>
- _logStatsVersion: use property assignment instead of postfix++ on
  cast expression, which is a no-op when Vue reactive() unwraps the ref
- _logStatsVersion: change from readonly to private readonly
- collectLogStats: use select with s.ctx.Done() when acquiring semaphore
  to avoid blocking the loop on context cancellation

Co-Authored-By: Zhuge <zhugehyuk@gmail.com>
Add allowed_bots: '*' to claude-code-action step to prevent
rejection of PRs opened by zhuge-liang-bot.

Co-Authored-By: Zhuge <zhugehyuk@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant