Skip to content

Collector Installation

Last updated

View as Markdown

DBGorilla reads metrics from your infrastructure through the DBGorilla Collector. Wherever you run it, the collector needs the same three things: a database login with the right grants, a collector.toml, and outbound network access. This page covers all three. Pick your deployment target from the pages that follow.

The collector reads PostgreSQL statistics directly and, for host statistics, talks to the Prometheus node_exporter. You need one collector per network segment, and node_exporter on each database host you want host metrics from.

On managed platforms like AWS RDS, where you have no access to the database host, the collector reads equivalent metrics from CloudWatch and node_exporter is not required.

The collector is a custom OpenTelemetry collector, shipped as a Docker image, that runs anywhere a Linux container runs. You configure it with a single file mounted into the container. The app shows you that file when you add a collector.

A collector reads from one or more components. A component is a logical database endpoint: a single server, a cluster with readers and writers, or a cloud database endpoint. The collector must be able to reach each component on the database port (5432 for PostgreSQL) and, for physical hosts, the node_exporter port (9100 by default).

The collector needs outbound access to otlp.dbgorilla.com and auth.dbgorilla.com on port 443, and nothing else. It listens on no inbound port. Metrics travel over the OpenTelemetry Protocol (OTLP); management traffic uses the Open Agent Management Protocol (OpAMP).

Create a dedicated read-only login for the collector. “Read-only” is several grants, not one:

CREATE ROLE dbg_readonly LOGIN PASSWORD 'replace-me';
GRANT pg_monitor TO dbg_readonly; -- cluster-wide stats
GRANT USAGE ON SCHEMA public TO dbg_readonly; -- per schema you want captured
GRANT SELECT ON ALL TABLES IN SCHEMA public TO dbg_readonly;
ALTER DEFAULT PRIVILEGES FOR ROLE app_owner IN SCHEMA public
GRANT SELECT ON TABLES TO dbg_readonly; -- tables created later

Replace app_owner with the role that creates your tables, and repeat the statement for each one. ALTER DEFAULT PRIVILEGES without FOR ROLE covers only tables created by the role running it. If your application creates tables as its own role and you ran the command as postgres, new tables are not covered, and you land in the failure below the first time your application migrates. List the roles that own tables with:

SELECT DISTINCT tableowner FROM pg_tables WHERE schemaname NOT IN ('pg_catalog','information_schema');

CREATE ROLE and GRANT pg_monitor are cluster-wide, so run them once. The USAGE and SELECT grants are not. They apply only to the database you are connected to and the schema you name, so run them again for every database you list in databases, and once per schema inside it. Grant them in one database only and you land in the failure below.

pg_monitor alone is not enough, and the failure is quiet: the collector connects and reports metrics normally, then fails every schema capture with permission denied for table …, logged as a warning that retries forever. The collector looks healthy and captures no schema at all. Schema capture runs pg_dump, which must SELECT every table it reads.

pg_stat_statements is required for full functionality. It is the PostgreSQL extension that records how long each statement takes and how often it runs. Everything DBGorilla tells you about query performance comes from it.

Without it, the collector still connects and still reports host metrics, database size, table statistics and cluster topology. What you lose is every query-level feature: slow query analysis, query-level recommendations, and anything that ranks statements by cost. The collector will not tell you this is missing once it is running, so check it up front:

SELECT * FROM pg_available_extensions WHERE name = 'pg_stat_statements';
SHOW shared_preload_libraries;

Loading it takes a full server restart, not a reload, because it hooks into the executor at startup. One caution before you run it: ALTER SYSTEM SET replaces the whole value, it does not append. Read the current setting first and include everything already there, or you will unload another extension at the next restart.

SHOW shared_preload_libraries;
-- if it is empty:
ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';
-- if it already lists something, repeat every existing entry, for example:
ALTER SYSTEM SET shared_preload_libraries = 'pg_cron,pg_stat_statements';
-- restart PostgreSQL, then:
CREATE EXTENSION pg_stat_statements;

On managed platforms you set it through the provider instead: a parameter group on AWS RDS and Aurora, server parameters on Azure Database for PostgreSQL, or database flags on Cloud SQL. Each still needs a restart.

The example below runs one collector against one PostgreSQL cluster (db-cluster1.internal.example.com), restricted to a single database.

The agent ID and secret are issued per collector; the tenant ID identifies your organization and is shared across all of its collectors. All three are shown when you add a collector in the app.

Keep secrets out of the file. Reference them as ${VAR} and supply the values as environment variables, from whatever secrets manager you already use.

[dbgorilla]
agent_id = "a8c1cde3-3e91-4ecf-b615-26bae0c35f02"
tenant_id = "fd4c6676-c1a1-4d9a-babb-54958c26369d"
secret = "${DBG_SERVER_SECRET}"
# One [[component]] block per database system to monitor.
[[component]]
name = "example_db" # the name your system appears under in DBGorilla
engine = "postgres"
[component.provider]
type = "self_hosted"
[component.auth]
method = "password"
user = "dbg_readonly"
password = "${DB_PASSWORD}"
[component.connect]
host = "db-cluster1.internal.example.com"
port = 5432
databases = ["example_db"] # empty = all non-template databases
ssl_mode = "verify-full" # disable | require | verify-ca | verify-full
[commands]
# Optional. When enabled, allows explain and execute_query (see below).
enabled = true
# allowed = ["explain"] # optional: further restrict to a subset

The endpoints default to otlp.dbgorilla.com and auth.dbgorilla.com, so most configurations do not set them at all.

verify-full is the right choice whenever the database is reached over a network, and it works against managed databases whose certificates chain to a public authority.

If your server presents a certificate from an internal authority, which is what most Kubernetes-operator-managed PostgreSQL does, then verify-full and verify-ca fail on trust, because the container has no reason to hold your CA. Either mount your CA into the container and point ca_cert at it, or use require, which keeps the connection encrypted but skips certificate verification.

Use disable only for a database on the same machine as the collector. Over a network it sends the password and every query in clear text.

The [commands] block is optional. When enabled, it lets the control plane run a fixed set of read-oriented operations through the collector:

  • explain: plan-only EXPLAIN. Never EXPLAIN ANALYZE; the query is not executed.
  • execute_query: a single SELECT, capped at 1,000 rows with a 30-second statement timeout.

Disable it and the collector cannot execute either. Anything that does run is still bounded by the privileges of the database user you configured. The collector cannot escalate beyond that user.