Skip to content

feat: view full log line in monit dashboard - #6137

Open
ButchAnton wants to merge 1 commit into
Unitech:developmentfrom
ButchAnton:feat/monit-log-line-detail
Open

feat: view full log line in monit dashboard#6137
ButchAnton wants to merge 1 commit into
Unitech:developmentfrom
ButchAnton:feat/monit-log-line-detail

Conversation

@ButchAnton

Copy link
Copy Markdown

Problem

The Logs panel in pm2 monit / pm2 dashboard (lib/API/Dashboard.js)
renders each entry as one row in a blessed.list. Anything wider than the
panel is silently clipped, with no way to see the rest — no wrapping, no
horizontal scroll, no detail view. Long lines (stack traces, JSON payloads,
long URLs, etc.) are simply unreadable in the dashboard today.

What this adds

Pressing Enter on a selected line in the Logs panel opens a scrollable
overlay with:

  • The full, wrapped, untruncated text of that line
  • Process name
  • Stream (stdout / stderr / pm2-internal)
  • When the dashboard received it
  • A best-effort detected timestamp and log level, parsed out of the line's
    own text (many apps prefix their own lines with these, independent of
    pm2's stream typing)

Pressing Enter again closes the overlay and returns focus to the Logs panel.
The footer hint text is updated accordingly.

Implementation notes

  • A parallel rawLogLines buffer stores untruncated text + metadata per
    line, evicted in lockstep with the existing logLines (display strings)
    buffer, so memory usage is unaffected.
  • The overlay listens for List's select event (emitted only from
    enterSelected, i.e. an explicit Enter), not select item (emitted on
    every navigation via List.prototype.select, including the refresh-driven
    setItems() calls) — so it only opens on Enter, never as a side effect of
    scrolling or the dashboard's periodic refresh tick.
  • Log text coming through loggers like Winston can carry raw ANSI SGR codes
    around level words (e.g. "\x1b[32minfo\x1b[39m:"). Left in place, the
    escape sequence's trailing letter sits directly against the word with no
    regex word boundary between them, silently breaking level detection — so
    these are stripped before storage.

Testing

This file has no existing automated test coverage (it's a blessed
terminal UI with no headless test harness in this repo). I tested manually
via tmux (driving the real interactive dashboard with tmux send-keys /
capture-pane against live pm2-managed processes) and via a small
synthetic harness that calls Dashboard.init() / .log() /
.showLogDetail() directly to exercise ANSI-stripping and level-detection
against realistic Winston-colorized output. Verified:

  • Long lines (a 2000+ char JSON line) render fully wrapped in the overlay
  • Enter opens/closes the overlay correctly and returns focus to the Logs
    panel
  • Up/down scroll works inside the overlay for content taller than it
  • Detected timestamp/level render correctly, including with ANSI-colorized
    input
  • No regressions to existing board-switching (left/right) or quit
    (Escape/q/Ctrl-C) behavior

Made with Cursor

The Logs panel in `pm2 monit`/`pm2 dashboard` renders each entry as one
row in a blessed list, so anything wider than the panel is silently
clipped with no way to see the rest - no wrapping, no horizontal
scroll, no detail view.

This adds one: pressing Enter on a selected line in the Logs panel
opens a scrollable overlay with the full, wrapped, untruncated text,
plus a bit of parsed context - process name, stream (stdout/stderr/pm2
internal), when the dashboard received it, and a best-effort detected
timestamp/log level pulled from the line's own text (many apps prefix
their own log lines with these, independent of pm2's stream typing).
Enter again closes the overlay.

Implementation notes:
- A parallel `rawLogLines` buffer stores untruncated text + metadata
  per line, evicted in lockstep with the existing `logLines` (display
  strings) buffer, so memory usage is unaffected.
- The overlay listens for List's `select` event (emitted only from
  `enterSelected`, i.e. Enter), not `select item` (emitted on every
  navigation via `List.prototype.select`, including the refresh-driven
  `setItems()` calls) - so it only opens on an explicit Enter press,
  never as a side effect of scrolling or the dashboard's periodic
  refresh.
- Log text coming through loggers like Winston can carry raw ANSI SGR
  codes around level words (e.g. "\x1b[32minfo\x1b[39m:"). Left in
  place, the escape sequence's trailing letter sits directly against
  the word with no regex word boundary between them, silently breaking
  level detection - so these are stripped before storage.

Co-authored-by: Cursor <cursoragent@cursor.com>
@CLAassistant

CLAassistant commented Jul 30, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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.

2 participants