Skip to content

Cleanup/add gitlab exporters #819

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
6323907
Add wal receiver
Sticksman Jun 16, 2023
8ee74db
Finish pg_stat_walreceiver
Sticksman Jun 20, 2023
0117653
Add pg_archiver
Sticksman Jun 20, 2023
eecb3ba
Missed a label declaration
Sticksman Jun 20, 2023
a6998af
Add stat_user_indexes
Sticksman Jun 20, 2023
dff617a
Add pg statio user queries and fix a test name
Sticksman Jun 22, 2023
4b3e95c
Migrate from db -> instance
Sticksman Jun 22, 2023
29736ce
pg_index_size query
Sticksman Jun 22, 2023
9198ec9
Add total relation size query
Sticksman Jun 22, 2023
c7dad9d
Add pg_blocked query
Sticksman Jun 23, 2023
fb04e3c
Add pg_blocked queries
Sticksman Jun 23, 2023
f76c2ce
Add pg_slow
Sticksman Jun 23, 2023
5d06f64
Add long running transactions query
Sticksman Jun 23, 2023
eb86b4c
Add stuck in transaction query + xid query + fix some init
Sticksman Jun 23, 2023
b235947
Add database wraparound query
Sticksman Jun 23, 2023
eac7650
Fix test name
Sticksman Jun 23, 2023
18ba5bb
xlog location
Sticksman Jun 23, 2023
bb5dba8
Add pg_stat_activity_marginalia sampler
Sticksman Jun 23, 2023
8bbd6d4
Add pg stat activity autovacuum
Sticksman Jun 23, 2023
82a51fe
Add autovacuum active
Sticksman Jun 23, 2023
c9f83ae
Long running transactions marginalia
Sticksman Jun 23, 2023
9b4d845
Lint fixes
Sticksman Jun 23, 2023
49e1a46
Lint
Sticksman Jun 23, 2023
d822ec4
Fix the NaN tests
Sticksman Jun 23, 2023
7651eed
Remove broken tests for now
Sticksman Jun 23, 2023
534af41
Lint
Sticksman Jun 23, 2023
8d6499f
Disable all new queries by default, rename marginalia -> summary
Sticksman Jun 23, 2023
4891644
Update pg_blocked with nulls
Sticksman Jun 26, 2023
4adddb3
Db wraparound test nullable
Sticksman Jun 26, 2023
8b7ffa6
index size nullable
Sticksman Jun 26, 2023
532c04f
LongRunningTransactionsSUmmary nullable
Sticksman Jun 26, 2023
f839778
stat user indexes nullable
Sticksman Jun 26, 2023
fddba48
stat walreceiver nil
Sticksman Jun 26, 2023
6513418
statiouser_indexes nullable
Sticksman Jun 26, 2023
aa910f3
total relation size nullable
Sticksman Jun 26, 2023
2d33e61
Remove linebreak
Sticksman Jun 26, 2023
55034b3
Use labels pattern
Sticksman Jun 26, 2023
57ea9d8
stat activity summary nullable
Sticksman Jun 26, 2023
3718e52
Redo all change requests
Sticksman Jun 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions collector/collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,12 @@ func readMetric(m prometheus.Metric) MetricResult {
func sanitizeQuery(q string) string {
q = strings.Join(strings.Fields(q), " ")
q = strings.Replace(q, "(", "\\(", -1)
q = strings.Replace(q, "?", "\\?", -1)
q = strings.Replace(q, ")", "\\)", -1)
q = strings.Replace(q, "[", "\\[", -1)
q = strings.Replace(q, "]", "\\]", -1)
q = strings.Replace(q, "*", "\\*", -1)
q = strings.Replace(q, "^", "\\^", -1)
q = strings.Replace(q, "$", "\\$", -1)
return q
}
81 changes: 81 additions & 0 deletions collector/pg_archiver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2023 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"

"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
)

func init() {
registerCollector("archiver", defaultDisabled, NewPGArchiverCollector)
}

type PGArchiverCollector struct {
log log.Logger
}

const archiverSubsystem = "archiver"

func NewPGArchiverCollector(config collectorConfig) (Collector, error) {
return &PGArchiverCollector{log: config.logger}, nil
}

var (
pgArchiverPendingWalCount = prometheus.NewDesc(
prometheus.BuildFQName(namespace, archiverSubsystem, "pending_wals"),
"Number of WAL files waiting to be archived",
[]string{}, prometheus.Labels{},
)

pgArchiverQuery = `
WITH
current_wal_file AS (
SELECT CASE WHEN NOT pg_is_in_recovery() THEN pg_walfile_name(pg_current_wal_insert_lsn()) ELSE NULL END pg_walfile_name
),
current_wal AS (
SELECT
('x'||substring(pg_walfile_name,9,8))::bit(32)::int log,
('x'||substring(pg_walfile_name,17,8))::bit(32)::int seg,
pg_walfile_name
FROM current_wal_file
),
archive_wal AS(
SELECT
('x'||substring(last_archived_wal,9,8))::bit(32)::int log,
('x'||substring(last_archived_wal,17,8))::bit(32)::int seg,
last_archived_wal
FROM pg_stat_archiver
)
SELECT coalesce(((cw.log - aw.log) * 256) + (cw.seg-aw.seg),'NaN'::float) as pending_wal_count FROM current_wal cw, archive_wal aw
`
)

func (c *PGArchiverCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
db := instance.getDB()
row := db.QueryRowContext(ctx,
pgArchiverQuery)
var pendingWalCount float64
err := row.Scan(&pendingWalCount)
if err != nil {
return err
}
ch <- prometheus.MustNewConstMetric(
pgArchiverPendingWalCount,
prometheus.GaugeValue,
pendingWalCount,
)
return nil
}
96 changes: 96 additions & 0 deletions collector/pg_archiver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2023 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"
"math"
"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"
)

func TestPgArchiverCollector(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}
mock.ExpectQuery(sanitizeQuery(pgArchiverQuery)).WillReturnRows(sqlmock.NewRows([]string{"pending_wal_count"}).
AddRow(5))

ch := make(chan prometheus.Metric)
go func() {
defer close(ch)
c := PGArchiverCollector{}

if err := c.Update(context.Background(), inst, ch); err != nil {
t.Errorf("Error calling PGArchiverCollector.Update: %s", err)
}
}()

expected := []MetricResult{
{labels: labelMap{}, value: 5, metricType: dto.MetricType_GAUGE},
}
convey.Convey("Metrics comparison", t, func() {
for _, expect := range expected {
m := readMetric(<-ch)
convey.So(expect, convey.ShouldResemble, m)
}
})
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled exceptions: %s", err)
}
}

func TestPgArchiverNaNCollector(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}
mock.ExpectQuery(sanitizeQuery(pgArchiverQuery)).WillReturnRows(sqlmock.NewRows([]string{"pending_wal_count"}).
AddRow(math.NaN()))

ch := make(chan prometheus.Metric)
go func() {
defer close(ch)
c := PGArchiverCollector{}

if err := c.Update(context.Background(), inst, ch); err != nil {
t.Errorf("Error calling PGArchiverCollector.Update: %s", err)
}
}()

expected := []MetricResult{
{labels: labelMap{}, value: math.NaN(), metricType: dto.MetricType_GAUGE},
}
convey.Convey("Metrics comparison", t, func() {
for _, expect := range expected {
m := readMetric(<-ch)
convey.So(expect.labels, convey.ShouldResemble, m.labels)
convey.So(math.IsNaN(m.value), convey.ShouldResemble, math.IsNaN(expect.value))
convey.So(expect.metricType, convey.ShouldEqual, m.metricType)
}
})
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled exceptions: %s", err)
}
}
101 changes: 101 additions & 0 deletions collector/pg_blocked.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2023 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/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
)

const blockedSubsystem = "blocked"

func init() {
registerCollector(blockedSubsystem, defaultDisabled, NewPGBlockedCollector)
}

type PGBlockedCollector struct {
log log.Logger
}

func NewPGBlockedCollector(config collectorConfig) (Collector, error) {
return &PGBlockedCollector{log: config.logger}, nil
}

var (
blockedQueries = prometheus.NewDesc(
prometheus.BuildFQName(namespace, blockedSubsystem, "queries"),
"The current number of blocked queries",
[]string{"table"},
prometheus.Labels{},
)

blockedQuery = `
SELECT
count(blocked.transactionid) AS queries,
'__transaction__' AS table
FROM pg_catalog.pg_locks blocked
WHERE NOT blocked.granted AND locktype = 'transactionid'
GROUP BY locktype
UNION
SELECT
count(blocked.relation) AS queries,
blocked.relation::regclass::text AS table
FROM pg_catalog.pg_locks blocked
WHERE NOT blocked.granted AND locktype != 'transactionid'
GROUP BY relation
`
)

func (PGBlockedCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error {
db := instance.getDB()
rows, err := db.QueryContext(ctx,
blockedQuery)

if err != nil {
return err
}
defer rows.Close()

for rows.Next() {
var table sql.NullString
var queries sql.NullFloat64

if err := rows.Scan(&queries, &table); err != nil {
return err
}

tableLabel := "unknown"
if table.Valid {
tableLabel = table.String
}

queriesMetric := 0.0
if queries.Valid {
queriesMetric = queries.Float64
}
ch <- prometheus.MustNewConstMetric(
blockedQueries,
prometheus.GaugeValue,
queriesMetric,
tableLabel,
)
}
if err := rows.Err(); err != nil {
return err
}
return nil
}
101 changes: 101 additions & 0 deletions collector/pg_blocked_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2023 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"
)

func TestPgBlockedCollector(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}
columns := []string{
"queries",
"table",
}
rows := sqlmock.NewRows(columns).
AddRow(1000, "pgbouncer")

mock.ExpectQuery(sanitizeQuery(blockedQuery)).WillReturnRows(rows)

ch := make(chan prometheus.Metric)
go func() {
defer close(ch)
c := PGBlockedCollector{}

if err := c.Update(context.Background(), inst, ch); err != nil {
t.Errorf("Error calling PGBlockedCollector.Update: %s", err)
}
}()
expected := []MetricResult{
{labels: labelMap{"table": "pgbouncer"}, value: 1000, metricType: dto.MetricType_GAUGE},
}
convey.Convey("Metrics comparison", t, func() {
for _, expect := range expected {
m := readMetric(<-ch)
convey.So(expect, convey.ShouldResemble, m)
}
})
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled exceptions: %s", err)
}
}

func TestPgBlockedCollectorNull(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}
columns := []string{
"queries",
"table",
}
rows := sqlmock.NewRows(columns).
AddRow(nil, nil)

mock.ExpectQuery(sanitizeQuery(blockedQuery)).WillReturnRows(rows)

ch := make(chan prometheus.Metric)
go func() {
defer close(ch)
c := PGBlockedCollector{}

if err := c.Update(context.Background(), inst, ch); err != nil {
t.Errorf("Error calling PGBlockedCollector.Update: %s", err)
}
}()
expected := []MetricResult{
{labels: labelMap{"table": "unknown"}, value: 0, metricType: dto.MetricType_GAUGE},
}
convey.Convey("Metrics comparison", t, func() {
for _, expect := range expected {
m := readMetric(<-ch)
convey.So(expect, convey.ShouldResemble, m)
}
})
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unfulfilled exceptions: %s", err)
}
}
Loading