Skip to content

feat(cli): live local dashboard for monitor - #1365

Open
davidberenstein1957 wants to merge 4 commits into
masterfrom
feat/monitor-live-ui
Open

feat(cli): live local dashboard for monitor#1365
davidberenstein1957 wants to merge 4 commits into
masterfrom
feat/monitor-live-ui

Conversation

@davidberenstein1957

Copy link
Copy Markdown
Collaborator

Closes #1348

What it adds

codecarbon monitor --ui serves a live view of the current run on http://127.0.0.1:8050: current power, cumulative gCO2eq, energy, elapsed time, a CPU/GPU/RAM power chart over the last samples, the detected hardware, and per-task rows when tasks are used.

It is a stdlib ThreadingHTTPServer on a daemon thread plus one self-contained HTML file. No new dependency, no build step, no database, no CDN, no network access — it works air-gapped and does not need the carbonboard extra or carbonserver.

User-facing surface

  • codecarbon monitor --ui [--ui-port 8050] [--ui-host 127.0.0.1], also on the wrapped form (codecarbon monitor --ui -- python train.py).
  • codecarbon.viz.live.LiveDashboardOutput, usable like any other output handler: EmissionsTracker(output_handlers=[LiveDashboardOutput()]).
  • Routes: / (page), /data (JSON), /health.
  • Loopback by default; a non-loopback bind logs a warning, since the server is unauthenticated by design. A busy port logs an error and monitoring continues without the UI.
  • Docs: new section in docs/how-to/visualize.md, options in docs/reference/cli.md.

One change outside the new files

live_out was only called every api_call_interval measures (5 minutes with the defaults), which is far too coarse for a live view. Handlers can now set live_out_every_measure = True to be called on every measurement instead, receiving the total with delta=None — the delta is deliberately not computed there, since _compute_emissions_delta consumes state used by the periodic call. Existing handlers are unaffected: the attribute defaults to False and is read with getattr, so duck-typed custom handlers keep working.

Verified

  • uv run pytest tests/test_live_dashboard.py -q — 8 tests: bounded history, /data payload, / and 404, /health, concurrent read/write returning valid JSON, port released on exit(), busy port stays inert, and the tracker feeding a sample per measure.
  • No regression in tests/test_custom_handler.py, tests/test_emissions_tracker.py, tests/cli, tests/test_docs_examples.py, tests/test_package_integrity.py.
  • Manual run: codecarbon monitor --ui --offline --country-iso-code FRA --measure-power-secs 3, samples appearing every 3 s and the page rendering.
  • black --check and ruff check scoped to the touched files (remaining ruff hits in cli/main.py are pre-existing).

Deliberately left out

  • Reading existing emissions.csv history — that is carbonboard's job; this only shows the current run.
  • Auth, TLS, persistence, websockets, config-file keys (ui, ui_port, ui_host). Flags seem enough for an interactive foreground command; happy to add the config keys if wanted.
  • A docs screenshot, which I cannot produce here — worth adding before merge.

🤖 Generated with Claude Code

Add `codecarbon monitor --ui`, serving a single self-contained page over a
stdlib HTTP server so a run can be watched while it happens, without the
carbonboard extra, carbonserver or any network access.

Output handlers can now opt into `live_out` on every measurement via
`live_out_every_measure`, instead of once per `api_call_interval`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.58%. Comparing base (065d0e6) to head (61a0472).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1365      +/-   ##
==========================================
+ Coverage   91.39%   91.58%   +0.18%     
==========================================
  Files          49       50       +1     
  Lines        5056     5145      +89     
==========================================
+ Hits         4621     4712      +91     
+ Misses        435      433       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

davidberenstein1957 and others added 3 commits August 12, 2026 19:26
Measure codecarbon/viz/live.py instead of omitting it with the legacy
Dash dashboard, and cover the paths the new feature added: the
--ui/--ui-port/--ui-host wiring (serving and busy-port branches),
task_out, out, the non-loopback bind warning, idempotent exit, and the
live_out_every_measure handling in the tracker.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The live chart read cpu/gpu/ram_power off EmissionsData, which holds the
average since start() (the _*_power_sum accumulators are never reset), so
the 'live power' line was a running mean that ramped up and then barely
decayed: measured 8.5 -> 35.7 -> 10.4 W of real power against a monotone
8.5 -> 22.6 -> 20.4 W average over the same idle/busy/idle run.

The tracker now hands the handler the last measured power, and handlers
opt into the per-measure cadence by defining `on_measure` instead of the
`live_out_every_measure` class attribute that widened BaseOutput for one
consumer. LiveDashboardOutput leaves `out`/`live_out` as no-ops so the
chart has a single feed of comparable samples.

Also append the live handler to output_handlers rather than replacing the
list.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.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.

Feature proposal: live local dashboard for codecarbon monitor --ui

1 participant