Skip to content

Add arbitrary labels on a per-database basis #287

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 28, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,14 @@ databases:
## Oracle Database Connection pool minimum size
# poolMinConnections: 15

## Arbitrary labels to add to each metric scraped from this database
# labels:
# - name: label_name
# value: label_value
# - name: label_name2
# value: label_value2


metrics:
## How often to scrape metrics. If not provided, metrics will be scraped on request.
# scrapeInterval: 15s
Expand Down Expand Up @@ -791,6 +799,18 @@ databases:
# poolMaxConnections: 15
## Oracle Database Connection pool minimum size
# poolMinConnections: 15

### Arbitrary labels to add to each metric scraped from this database
## Any labels configured for one database will be added to metrics from
## every database, because the same metric names must always have the same
## full labelset. If the label isn't set for a particular database, then it
## will just be set to an empty string.
# labels:
# - name: label_name
# value: label_value
# - name: label_name2
# value: label_value2

db2:
## Database username
username: ${DB2_USERNAME}
Expand Down Expand Up @@ -828,6 +848,17 @@ databases:
## Oracle Database Connection pool minimum size
# poolMinConnections: 15

### Arbitrary labels to add to each metric scraped from this database
## Any labels configured for one database will be added to metrics from
## every database, because the same metric names must always have the same
## full labelset. If the label isn't set for a particular database, then it
## will just be set to an empty string.
# labels:
# - name: label_name
# value: label_value
# - name: label_name2
# value: label_value2

metrics:
## How often to scrape metrics. If not provided, metrics will be scraped on request.
# scrapeInterval: 15s
Expand Down
18 changes: 17 additions & 1 deletion collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"io"
"log/slog"
"os"
"slices"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -50,9 +51,23 @@ func maskDsn(dsn string) string {
func NewExporter(logger *slog.Logger, m *MetricsConfiguration) *Exporter {
var databases []*Database
wg := &sync.WaitGroup{}

var allConstLabels []string
// All the metrics of the same name need to have the same labels
// If a label is set for a particular database, it must be included also
// in the same metrics collected from other databases. It will just be
// set to a blank value.
for _, dbconfig := range m.Databases {
for _, label := range dbconfig.Labels {
if (!slices.Contains(allConstLabels, label.Name)) {
allConstLabels = append(allConstLabels, label.Name)
}
}
}

for dbname, dbconfig := range m.Databases {
logger.Info("Initializing database", "database", dbname)
database := NewDatabase(logger, dbname, dbconfig)
database := NewDatabase(logger, dbname, dbconfig, allConstLabels)
databases = append(databases, database)
wg.Add(1)
go func() {
Expand Down Expand Up @@ -400,6 +415,7 @@ func (e *Exporter) scrapeGenericValues(d *Database, ch chan<- prometheus.Metric,
fieldToAppend string, ignoreZeroResult bool, request string, queryTimeout time.Duration) error {
metricsCount := 0
constLabels := d.constLabels()
e.logger.Debug("labels", constLabels)
genericParser := func(row map[string]string) error {
// Construct labels value
labelsValues := []string{}
Expand Down
6 changes: 6 additions & 0 deletions collector/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type DatabaseConfig struct {
URL string `yaml:"url"`
ConnectConfig `yaml:",inline"`
Vault *VaultConfig `yaml:"vault,omitempty"`
Labels []DatabaseLabel `yaml:"labels,omitempty"`
}

type ConnectConfig struct {
Expand Down Expand Up @@ -72,6 +73,11 @@ type LoggingConfig struct {
LogDestination string `yaml:"destination"`
}

type DatabaseLabel struct {
Name string `yaml:"name"`
Value string `yaml:"value"`
}

func (m *MetricsConfiguration) LogDestination() string {
return m.Logging.LogDestination
}
Expand Down
28 changes: 21 additions & 7 deletions collector/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,33 @@ func (d *Database) ping(logger *slog.Logger) error {
}

func (d *Database) constLabels() map[string]string {
return map[string]string{
Copy link
Member

@anders-swanson anders-swanson Jul 23, 2025

Choose a reason for hiding this comment

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

could be a function of the exporter now that it involves dynamic labels beyond what a given database has

// database name always included in constLabels
labels := map[string]string{
"database": d.Name,
}
// All the metrics of the same name need to have the same labels
// If a label is set for a particular database, it must be included also
// in the same metrics collected from other databases. It will just be
// set to a blank value.
for _, label := range d.allConstLabels {
labels[label] = ""
}
// configured per-database labels added to constLabels
for _, label := range d.Config.Labels {
labels[label.Name] = label.Value
}
return labels
}

func NewDatabase(logger *slog.Logger, dbname string, dbconfig DatabaseConfig) *Database {
func NewDatabase(logger *slog.Logger, dbname string, dbconfig DatabaseConfig, allConstLabels []string) *Database {
db, dbtype := connect(logger, dbname, dbconfig)
return &Database{
Name: dbname,
Up: 0,
Session: db,
Type: dbtype,
Config: dbconfig,
Name: dbname,
Up: 0,
Session: db,
Type: dbtype,
Config: dbconfig,
allConstLabels: allConstLabels,
}
}

Expand Down
11 changes: 6 additions & 5 deletions collector/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ type Exporter struct {
}

type Database struct {
Name string
Up float64
Session *sql.DB
Type float64
Config DatabaseConfig
Name string
Up float64
Session *sql.DB
Type float64
Config DatabaseConfig
allConstLabels []string
}

type Config struct {
Expand Down