Current section
Files
Jump to
Current section
Files
README.md
# PgHero
A performance dashboard for Postgres, as a **Phoenix library** or a **Docker image**.
This is an Elixir port of [ankane/pghero](https://github.com/ankane/pghero) 4.x.
## Docker
```sh
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](http://localhost:8080). See [guides/Docker.md](guides/Docker.md) for auth, host-machine databases, and stats capture.
Without Docker:
```sh
DATABASE_URL=postgres://user:pass@localhost/dbname mix pghero.server
```
## Installation (Phoenix)
Add to `mix.exs`:
```elixir
def deps do
[
{:pghero, "~> 0.1.0"}
]
end
```
Point it at your Ecto repo in `config/config.exs`:
```elixir
config :pghero, repo: MyApp.Repo
```
Mount it in `router.ex` behind your own authentication:
```elixir
import PgHeroWeb.Router
scope "/" do
pipe_through [:browser, :require_admin]
pghero "/pghero"
end
```
Then open `/pghero`.
## Dummy app
A host Phoenix app lives in `dummy/` so you can see the mount without wiring your own project:
```sh
cd dummy
docker compose up -d
mix setup
mix phx.server
```
Then open [http://localhost:4000/pghero](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):
```elixir
config :pghero,
repo: MyApp.Repo,
username: "link",
password: "hyrule"
```
Or pass credentials at mount time:
```elixir
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
```elixir
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:
```elixir
defmodule MyApp.Repo.Migrations.CreatePgheroStats do
use Ecto.Migration
def up, do: PgHero.Migrations.up()
def down, do: PgHero.Migrations.down()
end
```
Capture on a schedule (Oban, Quantum, or cron):
```elixir
PgHero.capture_query_stats() # every 5 minutes
PgHero.capture_space_stats() # daily
```
Or mix tasks:
```sh
mix pghero.capture_query_stats
mix pghero.capture_space_stats
```
## Configuration
```elixir
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: nil
```
Environment 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](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
```sh
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.