Skip to content

Add aurora_replica_status collector#1311

Open
megative wants to merge 2 commits into
prometheus-community:masterfrom
megative:feat/aurora-init-detection-and-replica-status
Open

Add aurora_replica_status collector#1311
megative wants to merge 2 commits into
prometheus-community:masterfrom
megative:feat/aurora-init-detection-and-replica-status

Conversation

@megative

@megative megative commented May 17, 2026

Copy link
Copy Markdown
Contributor

Summary

First PR in a series splitting #1308 (Aurora support) into one-PR-per-collector as requested by @sysadmind.

This PR adds:

  • Aurora auto-detection infrastructure on instance struct. Mirrors the existing version field pattern (per @SuperQ feedback). On everysetup(), a one-shot SELECT aurora_version() runs via sync.Once — exactly one probe per process lifetime. The result is cached in instance.isAurora and read by Aurora-specific collectors.

  • aurora_replica_status collector. Exposes the values from Aurora's aurora_replica_status() built-in: replica lag (per server), replay latency, and pending read IOs. Disabled by default (--collector.aurora_replica_status); on non-Aurora servers it short-circuits to ErrNoData cleanly.

Test plan

  • go build ./..., go vet ./..., go test ./... clean.
  • Tested live against an Aurora PostgreSQL 17.7.0 cluster — collector
    emits metrics; per-process aurora_version() probe fires exactly once.
  • Tested against vanilla PostgreSQL 17 — collector returns ErrNoData
    silently; no error logs.

Follow-up PRs in the series will add the remaining 8 Aurora collectors on top of this infrastructure.

Add the first Amazon Aurora PostgreSQL collector, with the supporting
Aurora detection infrastructure on the instance struct.

- instance.isAurora bool field, set by setup() via a one-shot
  SELECT aurora_version() (sync.Once, one probe per process)
- aurora_replica_status collector exposes replica lag, replay latency,
  and pending read IOs from aurora_replica_status(). Gated on
  instance.isAurora — on non-Aurora servers returns ErrNoData.
- Disabled by default; opt-in via --collector.aurora_replica_status.

First in a series of per-collector PRs splitting prometheus-community#1308 as requested by
@sysadmind.

Signed-off-by: Pavel K <megativ3@gmail.com>
@megative

Copy link
Copy Markdown
Contributor Author

hi @SuperQ @sysadmind
Could you guys please take a look? It would be great to deliver Aurora support to upstream.

@megative

Copy link
Copy Markdown
Contributor Author

@SuperQ @sysadmind guys, sorry for pushing but any luck you have a chance to review this one?

@ArthurSens ArthurSens left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disclaimer, I'm not a maintainer of postgres_exporter, I'm just trying to unload a bit of their review load :)

Comment thread CHANGELOG.md

* [CHANGE] ...
* [FEATURE] ...
* [FEATURE] Add `aurora_replica_status` collector for Amazon Aurora PostgreSQL, with Aurora auto-detection on the `instance` struct.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* [FEATURE] Add `aurora_replica_status` collector for Amazon Aurora PostgreSQL, with Aurora auto-detection on the `instance` struct.
* [FEATURE] Add `aurora_replica_status` collector for Amazon Aurora PostgreSQL.

The second part of the phrase seems like implementation details; the postgres_exporter end-user doesn't care what an "instance struct" is


var (
auroraReplicaLagDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, auroraReplicaSubsystem, "lag_milliseconds"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prometheus recommends using base units for metric units. We have a few examples of other collectors doing this transformation, like pg_setting and pg_stat_statements

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed. This should be converted.

[]string{"server_id"}, nil,
)
auroraReplayLatencyDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, auroraReplicaSubsystem, "replay_latency_microseconds"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same applies here

Comment thread collector/instance.go
Comment on lines 54 to 58
db, err := sql.Open("postgres", dsn)
if err != nil {
return nil, err
}
db.Close()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asking without thinking too much... could the aurora detection be made here? If I understand it correctly, this runs only once and never again. So if we made the detection here, it would make the sync.Once shenanigans unecessary

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm probably missing context too since I'm not a maintainer of this exporter, but I'm wondering why version detection isn't made here either

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also have the option to do detection where we do PostgreSQL instance version checks.

Comment thread collector/instance.go
Comment on lines +28 to 44
type auroraProbe struct {
once sync.Once
isAurora bool
}

type instance struct {
dsn string
db *sql.DB
version semver.Version

// isAurora is set by setup() via the shared auroraProbe (one-shot
// SELECT aurora_version() per process). Aurora-specific collectors
// gate on this field; on non-Aurora servers they short-circuit to
// ErrNoData.
isAurora bool
auroraProbe *auroraProbe
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isAurora set in both instance and auroraProbe? Seems like instance has access to two fields that have the same meaning/value

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need both. I think it's complicated and doesn't add much value.

Comment thread collector/instance.go
Comment on lines +87 to +92
if i.auroraProbe != nil {
i.auroraProbe.once.Do(func() {
i.auroraProbe.isAurora = detectAurora(i.db)
})
i.isAurora = i.auroraProbe.isAurora
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this sync.Once protection against the query that detects version. I'm not sure if I'm missing something, but looks like an overcomplication....?

// auroraReplicaStatusCollector exposes metrics from Aurora PostgreSQL's
// aurora_replica_status() function. Disabled by default because the function
// only exists on Aurora.
const auroraReplicaSubsystem = "aurora_replica"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's unintuitive for the subsystem and the collector name below to be different. Someone runs --collector.aurora_replica_status but the metrics are aurora_replace_*. These should match. Based on the table name, they should both be aurora_replica_status.

}()

// writer: 1 metric (pending_read_ios), reader: 3 metrics → 4 total
expected := 4

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only validates that we had 4 metrics, not what they were. It's incomplete.

Comment thread README.md
non-Aurora server they silently emit no data.

* `[no-]collector.aurora_replica_status`
Replica lag, replay latency, pending read IOs from `aurora_replica_status()`. (default: disabled)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think calling out each metric here makes it easy to miss when the collector changes.

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.

3 participants