Skip to content
122 changes: 122 additions & 0 deletions collector/pg_extensions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package collector

import (
"context"
"database/sql"
"github.com/go-kit/log"
"github.com/prometheus/client_golang/prometheus"
"strconv"
)

func init() {
registerCollector("extensions", defaultEnabled, NewExtensionsCollector)
Comment thread
ritbl marked this conversation as resolved.
}

var pgExtensions = map[string]*prometheus.Desc{
"pg_available_extensions": prometheus.NewDesc(
"pg_available_extensions",
"Extensions that are available for installation",
[]string{
"name",
"default_version",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

what does it mean default? used? I think we need a better name here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

these lablels are copies of column names from the table from which we fetch these metrics.

I believe it means if you install this extensions and not specify the version this default version will be used.

"installed_version",
},
prometheus.Labels{},
),
"pg_extensions": prometheus.NewDesc(
"pg_extensions",
"Installed extensions",
[]string{
"name",
"relocatable",
"version",
},
prometheus.Labels{},
),
}

type ExtensionsCollector struct {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

how about checking that struct implements interface?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

added it

logger log.Logger
}

func NewExtensionsCollector(logger log.Logger) (Collector, error) {
Comment thread
ritbl marked this conversation as resolved.
return &ExtensionsCollector{logger: logger}, nil
}

func (e *ExtensionsCollector) Update(ctx context.Context, server *server, ch chan<- prometheus.Metric) error {
db, err := server.GetDB()
if err != nil {
return err
}

err = e.scrapeAvailableExtensions(ctx, db, ch)
if err != nil {
return err
}

err = e.scrapeInstalledExtensions(ctx, db, ch)
if err != nil {
return err
}

return nil
}

func (e *ExtensionsCollector) scrapeInstalledExtensions(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error {
rowsExtensions, err := db.QueryContext(ctx, `SELECT extname, extrelocatable, extversion FROM pg_extension`)
Comment thread
ritbl marked this conversation as resolved.

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

for rowsExtensions.Next() {
var extname string
var extrelocatable bool
var extversion string
if err := rowsExtensions.Scan(&extname, &extrelocatable, &extversion); err != nil {
return err
}

ch <- prometheus.MustNewConstMetric(
pgExtensions["pg_extensions"],
prometheus.GaugeValue,
1,
extname,
strconv.FormatBool(extrelocatable),
extversion,
)
}

return nil
}

func (e *ExtensionsCollector) scrapeAvailableExtensions(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric) error {
rows, err := db.QueryContext(ctx, `SELECT name, default_version, installed_version FROM pg_available_extensions`)
Comment thread
ritbl marked this conversation as resolved.
if err != nil {
return err
}
defer rows.Close()

for rows.Next() {
var name sql.NullString
var defaultVersion sql.NullString
var installedVersion sql.NullString
if err := rows.Scan(&name, &defaultVersion, &installedVersion); err != nil {
return err
}

ch <- prometheus.MustNewConstMetric(
pgExtensions["pg_available_extensions"],
prometheus.GaugeValue,
1,
name.String,
defaultVersion.String,
installedVersion.String,
)
}

return nil
}

var _ = (Collector)(&ExtensionsCollector{})