Skip to content

nbari/pgmon

Repository files navigation

Test & Build codecov Crates.io License

pgmon

A PostgreSQL monitoring TUI inspired by pg_activity.

pgmon screenshot

Features

  • Real-time views of:
    • pg_stat_activity
    • pg_stat_replication / pg_replication_slots
    • pg_stat_database
    • pg_locks
    • pg_stat_io (PostgreSQL 16+)
    • pg_stat_statements (if extension exists)
  • Pg-activity-inspired Activity dashboard with sampled TPS/DML/temp rates, session counts, and worker/process summaries
  • Activity subviews for active, waiting, blocking, and idle in transaction backends
  • Contextual in-app help overlay (?) with current-view shortcuts and metric explanations
  • Built-in themes plus runtime theme switching and config validation with pgmon check-config
  • Interactive TUI (Tabs, Table navigation)
  • Configurable refresh rate and top-N rows.

Installation

cargo build --release

Usage

pgmon --dsn "postgresql://user:password@localhost:5432/postgres"

# Connect using an alias from pgmon.yaml or pgmon.yml
pgmon prod

# Load a specific config file
pgmon --config ./pgmon.yaml prod

# Use the config's default connection
pgmon --config ./pgmon.yaml

# Validate config loading and connection resolution without starting the TUI
pgmon check-config --config ./pgmon.yaml prod

# Specific home view and sort
pgmon --dsn "..." --home-view statements --sort total_time --top-n 20 --refresh-ms 2000

# Fail faster on unreachable hosts
pgmon --connect-timeout-ms 1500

# Save selected queries into a persistent directory
pgmon --query-output-dir "$HOME/.local/share/pgmon/queries"

# Or rely on PGMON_DSN / ~/.pgpass
PGMON_DSN="postgresql://postgres@localhost/postgres" pgmon

Configuration

pgmon supports a pgmon.yaml or pgmon.yml configuration file for connection aliases, UI preferences, built-in theme selection, custom named themes, and per-view colors.

If the config file does not define any connections, pgmon still starts normally and falls back to PGMON_DSN, then .pgpass.

The file is looked for in the following locations (in order):

  1. Path passed with -c, --config
  2. Current working directory (./pgmon.yaml, then ./pgmon.yml)
  3. User's configuration directory (~/.config/pgmon/pgmon.yaml, then ~/.config/pgmon/pgmon.yml on Linux/macOS)

An example config is available at the repository root as pgmon.yaml.

Example pgmon.yaml

# Optional default alias used when no positional alias is passed
default_connection: local

# Optional theme selection
# Built-in themes: calibrachoa, sky, mint, retro
theme: my_theme

# Named connections
connections:
  local:
    dsn: "postgresql://postgres:postgres@localhost:5432/postgres"
  prod:
    dsn: "postgresql://pgmon@prod.example.com/postgres"
  staging:
    dsn: "host=staging-db dbname=postgres user=pgmon password=secret"

# Optional custom theme templates
themes:
  my_theme:
    ui:
      header_border_color: "#95a8b8"
      footer_border_color: "#98aaa4"
    views:
      settings:
        colors:
          value: "#b4a9b7"

# Global UI preferences
# Top-level values override the selected theme
ui:
  show_controls: true # Set to false to hide the Controls section
  default_export_format: "csv" # or "json"

# Customize UI colors for specific views
# Top-level values override the selected theme
views:
  settings:
    colors:
      value: "#a8a0b4" # Optional muted override for the 'Value' column

Built-in themes are available even without a config file: calibrachoa, sky, mint, and retro. Colors can be specified by name (e.g., "red", "green", "blue", "yellow", "cyan", "magenta", "white", "black") or as #RRGGBB hex values for softer palettes. The my_theme example above is only illustrative; you can remove it entirely and select a built-in theme by name. Connection aliases are selected with pgmon <alias>. If default_connection is set, pgmon can start without a positional alias and will use that configured target. If --dsn is also provided, the explicit DSN takes precedence over both the positional alias and default_connection. Current config support is limited to the keys above; PGMON_DSN_* environment switching remains future work.

When themes are available, press T inside the TUI to switch between them at runtime. Theme switching is applied immediately for the current session; edit pgmon.yaml or pgmon.yml if you want the new theme to persist across restarts. If a custom YAML theme uses the same name as a built-in theme, the custom definition overrides the built-in one.

CLI Options

  • -d, --dsn <STRING>: PostgreSQL connection string (optional if PGMON_DSN or .pgpass is available)
  • [ALIAS]: Optional connection alias from pgmon.yaml or pgmon.yml
  • -c, --config <PATH>: Explicit path to pgmon.yaml or pgmon.yml
  • --connect-timeout-ms <u64>: Connection timeout in milliseconds (default: 3000)
  • --query-output-dir <PATH>: Directory used when saving selected queries with Enter
  • -r, --refresh-ms <u64>: Refresh interval (default: 1000)
  • -n, --top-n <u32>: Rows to show (default: 10)
  • --home-view <activity|statements>: Initial view
  • -s, --sort <total_time|mean_time|calls>: Statements sort column (default: total_time)
  • -v: Verbose logging

Connection precedence is: explicit --dsn, then positional alias from pgmon.yaml or pgmon.yml, then default_connection, then PGMON_DSN, then the first usable entry in PGPASSFILE or ~/.pgpass. If no aliases are configured at all, the resolution simply continues to PGMON_DSN and .pgpass.

TUI Shortcuts

  • 1-8: switch tabs
  • h / l: previous or next tab
  • j / k: move selection up or down
  • /: search or filter the current view
  • e: export the current table as CSV or JSON in Activity and Statements
  • m: cycle the Activity chart between Connections, TPS, DML/s, Temp Bytes/s, and Growth Bytes/s
  • T: open the theme picker when built-in or custom themes are available
  • ?: open contextual in-app help for the current view
  • q: quit or close the current modal

Config Validation

Use pgmon check-config to validate configuration loading and the effective connection resolution without starting the TUI.

Examples:

pgmon check-config
pgmon check-config prod
pgmon check-config --config ./pgmon.yaml prod
pgmon check-config --dsn "postgresql://postgres@localhost/postgres"

The report includes:

  • which config file was loaded, or whether built-in defaults are being used
  • configured aliases, default connection, and active theme
  • invalid color or alias/default-connection issues
  • the effective connection source (--dsn, alias, PGMON_DSN, or .pgpass)
  • a safe connection target summary without printing passwords

Connection & Capability Status

  • The Activity summary now shows the current connection target, observed refresh latency, and last successful refresh state.
  • The footer highlights offline/reconnect state when background refreshes fail and shows a slow-link indicator when refreshes exceed the configured interval.
  • Statements, IO, and Replication now show explicit capability panels when pg_stat_statements, pg_stat_io, or replication settings are unavailable instead of rendering synthetic placeholder rows.
  • On slower or remote links, pgmon reduces extra metadata round trips by caching capability checks and uses the observed refresh latency to avoid overly aggressive background polling.

Query Inspection

pgmon has two query-inspection flows:

  • In Statements, press i on the selected row to open a detail modal with the database name, full SQL text, and aggregated timing counters from pg_stat_statements.
  • In Activity, press i on the selected session to inspect the current query text for that backend and optionally run EXPLAIN (ANALYZE, BUFFERS).

Inside the query detail modal:

  • Enter saves the SQL text to --query-output-dir or the system temp directory.
  • x runs EXPLAIN (ANALYZE, BUFFERS) only for queries opened from Activity.

Normalized Query Limitation

pg_stat_statements often stores normalized SQL such as:

SELECT * FROM accounts WHERE id = $1

Those placeholders do not include actual runtime values, so pgmon cannot safely execute EXPLAIN ANALYZE for them.

For that reason, Statements is now an inspect-only view for query text and aggregated timings. Its detail modal does not offer EXPLAIN ANALYZE, because the SQL usually represents a normalized statement shape rather than one executable statement with real values.

When a normalized query is opened from Activity:

  • the modal shows a warning
  • the x action is marked as unavailable
  • pressing x keeps the modal open and shows a notice instead of sending the query to PostgreSQL

If you need an execution plan for a normalized statement, copy the SQL and replace $1, $2, and similar placeholders with real literal values in a separate session before running EXPLAIN.

View Notes

  • In the Database view, press Enter on a selected database row to browse schemas and tables for that database, and press Esc to return to the summary view.
  • In the Activity view, use a, w, b, and t to switch between active, waiting, blocking, and idle-in-transaction session subviews.
  • In the Activity view, press m to cycle the chart between Connections, TPS, DML/s, Temp Bytes/s, and Growth Bytes/s without triggering a refresh.
  • Press ? in any main view to open contextual help with that view's shortcuts, important limitations, and brief metric explanations.

About

Real-time PostgreSQL CLI monitoring

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors