A performance dashboard for Postgres, as a Phoenix library or a Docker image.
This is an Elixir port of ankane/pghero 4.x.
Docker
docker build -t pghero .
docker run --rm -ti -e DATABASE_URL=postgres://user:password@hostname:5432/dbname -p 8080:8080 pghero
Then visit http://localhost:8080. See guides/Docker.md for auth, host-machine databases, and stats capture.
Without Docker:
DATABASE_URL=postgres://user:pass@localhost/dbname mix pghero.server
Installation (Phoenix)
Add to mix.exs:
def deps do
[
{:pghero, "~> 0.1.0"}
]
endPoint it at your Ecto repo in config/config.exs:
config :pghero, repo: MyApp.RepoMount it in router.ex behind your own authentication:
import PgHeroWeb.Router
scope "/" do
pipe_through [:browser, :require_admin]
pghero "/pghero"
endThen open /pghero.
Dummy app
A host Phoenix app lives in dummy/ so you can see the mount without wiring your own project:
cd dummy
docker compose up -d
mix setup
mix phx.server
Then open http://localhost:4000/pghero.
Authentication
PgHero does not authenticate by itself when you mount it in a Phoenix pipeline. Put it behind your admin plug, as in the example above.
Optional HTTP basic auth (in addition to, or instead of, your pipeline):
config :pghero,
repo: MyApp.Repo,
username: "link",
password: "hyrule"Or pass credentials at mount time:
pghero "/pghero", username: "link", password: "hyrule"Do not expose this dashboard on the public internet without auth. It can show query text and kill backends.
Multiple databases
config :pghero,
databases: [
primary: [repo: MyApp.Repo],
analytics: [url: System.get_env("ANALYTICS_DATABASE_URL"), name: "Analytics"]
]Each entry accepts :repo, :url, and :name.
What you get
Same dashboard as the Rails engine:
- Overview (connections, vacuums, sequences, invalid indexes, slow queries)
- Queries (
pg_stat_statements) - Space
- Connections
- Live queries (with kill)
- Maintenance
- Explain
- Tune
Requires PostgreSQL 14+.
Query stats
Enable pg_stat_statements in postgresql.conf:
shared_preload_libraries = 'pg_stat_statements'Restart Postgres, then enable the extension from the Overview page (or CREATE EXTENSION pg_stat_statements).
Historical stats
Create the tables with an Ecto migration:
defmodule MyApp.Repo.Migrations.CreatePgheroStats do
use Ecto.Migration
def up, do: PgHero.Migrations.up()
def down, do: PgHero.Migrations.down()
endCapture on a schedule (Oban, Quantum, or cron):
PgHero.capture_query_stats() # every 5 minutes
PgHero.capture_space_stats() # dailyOr mix tasks:
mix pghero.capture_query_stats
mix pghero.capture_space_stats
Configuration
config :pghero,
repo: MyApp.Repo,
long_running_query_sec: 60,
slow_query_ms: 20,
slow_query_calls: 100,
total_connections_threshold: 500,
explain: true, # true | false | "analyze"
disable_kill: false,
username: nil,
password: nilEnvironment variables from the original project still work (PGHERO_USERNAME, PGHERO_PASSWORD, PGHERO_DATABASE_URL, and the threshold vars).
Permissions
Use a dedicated Postgres role. See guides/Permissions.md.
Not in this port yet
- Suggested indexes (
pg_query) - AWS RDS / GCP Cloud SQL system charts
- Query text filtering via
pg_query
Development
mix deps.get
mix test
just all-tests
just all-tests starts Postgres (via dummy/docker-compose.yml), creates pghero_test, and runs unit plus integration tests.
License
MIT. Original work by Andrew Kane; Elixir/Phoenix port of the same dashboard.