1
0
mirror of https://github.com/prometheus-community/postgres_exporter.git synced 2026-10-23 12:08:57 +03:00

Add aurora_global_db_instance_status collector for Amazon Aurora PostgreSQL (#1411)

Expose how far each instance, including the cross-Region replicas of an
Aurora global database, lags behind the writer, from
aurora_global_db_instance_status(), converted to seconds. The writer
reports NULL lag, so no lag is exported for it. aws_region is a label
because the same server_id can appear in several Regions.

The collector is disabled by default and returns no data on non-Aurora
servers.

Aurora collector names get their own block in config.go, so gofmt
does not realign the main list when longer names are added.

Signed-off-by: Pavel K <megativ3@gmail.com>
This commit is contained in:
Pavel K
2026-10-22 14:21:21 +02:00
committed by GitHub
parent 02d6977a2f
commit e9e1960b15
6 changed files with 227 additions and 9 deletions

View File

@@ -43,6 +43,7 @@ the `-file` flags at a mounted secret.
* [FEATURE] Add `aurora_stat_logical_wal_cache` collector for Amazon Aurora PostgreSQL by @megative in https://github.com/prometheus-community/postgres_exporter/pull/1414
* [BUGFIX] Fix the `replication` collector failing on every scrape on Amazon Aurora PostgreSQL, where it now reports only `pg_replication_is_replica`, by @megative in https://github.com/prometheus-community/postgres_exporter/pull/1424, based on the contribution by @dannotripp in https://github.com/prometheus-community/postgres_exporter/pull/1274
* [FEATURE] Add `aurora_stat_database` collector for Amazon Aurora PostgreSQL by @megative in https://github.com/prometheus-community/postgres_exporter/pull/1425
* [FEATURE] Add `aurora_global_db_instance_status` collector for Amazon Aurora PostgreSQL by @megative in https://github.com/prometheus-community/postgres_exporter/pull/1411
## 0.20.1 / 2026-07-07

View File

@@ -103,6 +103,9 @@ This will build the docker image as `prometheuscommunity/postgres_exporter:${bra
Show context-sensitive help (also try --help-long and --help-man).
* `[no-]collector.aurora_global_db_instance_status`
Enable the `aurora_global_db_instance_status` collector (default: disabled).
* `[no-]collector.aurora_global_db_status`
Enable the `aurora_global_db_status` collector (default: disabled).

View File

@@ -0,0 +1,87 @@
// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package collector
import (
"context"
"database/sql"
"github.com/prometheus/client_golang/prometheus"
)
const auroraGlobalDBInstanceStatusSubsystem = "aurora_global_db_instance_status"
func init() {
registerCollector(auroraGlobalDBInstanceStatusSubsystem, serverScope, NewAuroraGlobalDBInstanceStatusCollector)
}
// AuroraGlobalDBInstanceStatusCollector exposes metrics from Amazon Aurora
// PostgreSQL's aurora_global_db_instance_status() function: how far each
// instance, including the cross-Region replicas of an Aurora global
// database, lags behind the writer. It reports no data on servers that are
// not Aurora.
type AuroraGlobalDBInstanceStatusCollector struct{}
func NewAuroraGlobalDBInstanceStatusCollector(collectorConfig) (Collector, error) {
return &AuroraGlobalDBInstanceStatusCollector{}, nil
}
var (
auroraGlobalDBInstanceStatusVisibilityLag = prometheus.NewDesc(
prometheus.BuildFQName(namespace, auroraGlobalDBInstanceStatusSubsystem, "visibility_lag_seconds"),
"How far the instance lags behind the writer instance in seconds.",
[]string{"server_id", "aws_region"}, nil,
)
auroraGlobalDBInstanceStatusQuery = `SELECT
server_id,
aws_region,
visibility_lag_in_msec
FROM aurora_global_db_instance_status()`
)
func (c AuroraGlobalDBInstanceStatusCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
if !instance.isAurora {
return ErrNoData
}
rows, err := instance.getDB().QueryContext(ctx, auroraGlobalDBInstanceStatusQuery)
if err != nil {
return err
}
defer rows.Close()
var found bool
for rows.Next() {
found = true
var serverID, awsRegion string
var visibilityLagMsec sql.NullFloat64
if err := rows.Scan(&serverID, &awsRegion, &visibilityLagMsec); err != nil {
return err
}
// The writer reports NULL: it doesn't lag behind itself.
if visibilityLagMsec.Valid {
ch <- prometheus.MustNewConstMetric(auroraGlobalDBInstanceStatusVisibilityLag, prometheus.GaugeValue, visibilityLagMsec.Float64/1e3, serverID, awsRegion)
}
}
if err := rows.Err(); err != nil {
return err
}
if !found {
return ErrNoData
}
return nil
}

View File

@@ -0,0 +1,124 @@
// Copyright The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package collector
import (
"context"
"testing"
"github.com/DATA-DOG/go-sqlmock"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/smartystreets/goconvey/convey"
)
var auroraGlobalDBInstanceStatusColumns = []string{
"server_id",
"aws_region",
"visibility_lag_in_msec",
}
func TestAuroraGlobalDBInstanceStatusCollector(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("Error opening a stub db connection: %s", err)
}
defer db.Close()
inst := &instance{db: db, isAurora: true}
// The writer reports NULL visibility lag, so nothing is emitted for it.
// The same server_id can appear in several Regions.
rows := sqlmock.NewRows(auroraGlobalDBInstanceStatusColumns).
AddRow("instance-01", "eu-west-1", nil).
AddRow("instance-02", "eu-west-1", 6).
AddRow("global-instance-1", "eu-central-1", 996).
AddRow("global-instance-1", "eu-west-2", 14)
mock.ExpectQuery(sanitizeQuery(auroraGlobalDBInstanceStatusQuery)).WillReturnRows(rows)
ch := make(chan prometheus.Metric)
go func() {
defer close(ch)
c := AuroraGlobalDBInstanceStatusCollector{}
if err := c.Update(context.Background(), inst, ch); err != nil {
t.Errorf("Error calling AuroraGlobalDBInstanceStatusCollector.Update: %s", err)
}
}()
expected := []struct {
desc *prometheus.Desc
result MetricResult
}{
{auroraGlobalDBInstanceStatusVisibilityLag, MetricResult{labels: labelMap{"server_id": "instance-02", "aws_region": "eu-west-1"}, value: 0.006, metricType: dto.MetricType_GAUGE}},
{auroraGlobalDBInstanceStatusVisibilityLag, MetricResult{labels: labelMap{"server_id": "global-instance-1", "aws_region": "eu-central-1"}, value: 0.996, metricType: dto.MetricType_GAUGE}},
{auroraGlobalDBInstanceStatusVisibilityLag, MetricResult{labels: labelMap{"server_id": "global-instance-1", "aws_region": "eu-west-2"}, value: 0.014, metricType: dto.MetricType_GAUGE}},
}
convey.Convey("Metrics comparison", t, func() {
for _, expect := range expected {
m := <-ch
convey.So(m.Desc(), convey.ShouldEqual, expect.desc)
convey.So(readMetric(m), convey.ShouldResemble, expect.result)
}
_, more := <-ch
convey.So(more, convey.ShouldBeFalse)
})
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled exceptions: %s", err)
}
}
func TestAuroraGlobalDBInstanceStatusCollectorNotAurora(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("Error opening a stub db connection: %s", err)
}
defer db.Close()
// No query is expected: the collector must not touch the database when
// the server is not Aurora.
inst := &instance{db: db, isAurora: false}
ch := make(chan prometheus.Metric, 1)
c := AuroraGlobalDBInstanceStatusCollector{}
if err := c.Update(context.Background(), inst, ch); err != ErrNoData {
t.Errorf("Expected ErrNoData on non-Aurora server, got: %v", err)
}
if len(ch) != 0 {
t.Errorf("Expected no metrics on non-Aurora server, got %d", len(ch))
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled exceptions: %s", err)
}
}
func TestAuroraGlobalDBInstanceStatusCollectorNoRows(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("Error opening a stub db connection: %s", err)
}
defer db.Close()
inst := &instance{db: db, isAurora: true}
mock.ExpectQuery(sanitizeQuery(auroraGlobalDBInstanceStatusQuery)).WillReturnRows(sqlmock.NewRows(auroraGlobalDBInstanceStatusColumns))
ch := make(chan prometheus.Metric, 1)
c := AuroraGlobalDBInstanceStatusCollector{}
if err := c.Update(context.Background(), inst, ch); err != ErrNoData {
t.Errorf("Expected ErrNoData, got: %v", err)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled exceptions: %s", err)
}
}

View File

@@ -73,10 +73,11 @@ const (
CollectorXlogLocation = "xlog_location"
// Amazon Aurora PostgreSQL collectors.
CollectorAuroraGlobalDBStatus = "aurora_global_db_status"
CollectorAuroraReplicaStatus = "aurora_replica_status"
CollectorAuroraStatDatabase = "aurora_stat_database"
CollectorAuroraStatLogicalWalCache = "aurora_stat_logical_wal_cache"
CollectorAuroraGlobalDBInstanceStatus = "aurora_global_db_instance_status"
CollectorAuroraGlobalDBStatus = "aurora_global_db_status"
CollectorAuroraReplicaStatus = "aurora_replica_status"
CollectorAuroraStatDatabase = "aurora_stat_database"
CollectorAuroraStatLogicalWalCache = "aurora_stat_logical_wal_cache"
)
type Config struct {
@@ -235,10 +236,11 @@ func DefaultCollectorConfig() map[string]bool {
CollectorXlogLocation: false,
// Amazon Aurora PostgreSQL collectors.
CollectorAuroraGlobalDBStatus: false,
CollectorAuroraReplicaStatus: false,
CollectorAuroraStatDatabase: false,
CollectorAuroraStatLogicalWalCache: false,
CollectorAuroraGlobalDBInstanceStatus: false,
CollectorAuroraGlobalDBStatus: false,
CollectorAuroraReplicaStatus: false,
CollectorAuroraStatDatabase: false,
CollectorAuroraStatLogicalWalCache: false,
}
}

View File

@@ -64,8 +64,9 @@ and `datname` labels; update dashboards and alerts to use the names without
| `wal` | enabled | Number of WAL segment files and their total size on disk, via `pg_ls_waldir()`. On Amazon Aurora PostgreSQL versions that don't support `pg_ls_waldir()`, it reports nothing. |
| `stat_wal_receiver` | disabled | Seen from a standby: the WAL receiver's LSNs, timeline, upstream node, and last message send/receipt times. Enable this on replicas for a view of the receiving side. From `pg_stat_wal_receiver`. |
| `xlog_location` | disabled | Current WAL write position (or replay position on a replica) as a byte offset. Superseded by `stat_replication`; retained for old setups and pre-10 servers. |
| `aurora_replica_status` | disabled | **Amazon Aurora PostgreSQL only.** For each instance in the cluster: replica lag behind the writer, replay latency, and pending page reads. On non-Aurora servers it reports nothing. From `aurora_replica_status()`. |
| `aurora_global_db_instance_status` | disabled | **Amazon Aurora PostgreSQL only.** For each instance, including the cross-Region replicas of an Aurora global database: how far it lags behind the writer, in seconds. On non-Aurora servers it reports nothing. From `aurora_global_db_instance_status()`. |
| `aurora_global_db_status` | disabled | **Amazon Aurora PostgreSQL only.** For each secondary cluster of an Aurora global database, by AWS Region: storage (durability) lag and recovery point objective (RPO) lag behind the primary cluster, in seconds. On non-Aurora servers it reports nothing. From `aurora_global_db_status()`. |
| `aurora_replica_status` | disabled | **Amazon Aurora PostgreSQL only.** For each instance in the cluster: replica lag behind the writer, replay latency, and pending page reads. On non-Aurora servers it reports nothing. From `aurora_replica_status()`. |
| `aurora_stat_logical_wal_cache` | disabled | **Amazon Aurora PostgreSQL only.** Per logical replication slot: WAL cache hits, misses, and read requests. Requires Aurora PostgreSQL 11.17, 12.12, 13.8, 14.7, 15.2 or later; on older versions and on non-Aurora servers it reports nothing. From `aurora_stat_logical_wal_cache()`. |
### Checkpoints, buffers, and I/O