gitlab.com/gitlab-org/labkit@v1.21.0/metrics/sqlmetrics/dbstats.go (about)

     1  package sqlmetrics
     2  
     3  import (
     4  	"database/sql"
     5  
     6  	"github.com/prometheus/client_golang/prometheus"
     7  )
     8  
     9  const (
    10  	namespace   = "go_sql_dbstats"
    11  	subsystem   = "connections"
    12  	dbNameLabel = "db_name"
    13  
    14  	// Names for the recorded metrics.
    15  	maxOpenConnectionsName = "max_open"
    16  	openConnectionsName    = "open"
    17  	inUseName              = "in_use"
    18  	idleName               = "idle"
    19  	waitCountName          = "waits_total"
    20  	waitDurationName       = "wait_seconds_total"
    21  	maxIdleClosedName      = "max_idle_closed_count_total"
    22  	maxIdleTimeClosedName  = "max_idle_time_closed_count_total"
    23  	maxLifetimeClosedName  = "max_lifetime_closed_count_total"
    24  
    25  	// Descriptions for the recorded metrics.
    26  	maxOpenConnectionsDesc = "The limit of open connections to the database."
    27  	openConnectionsDesc    = "The number of established connections both in use and idle."
    28  	inUseDesc              = "The number of connections currently in use."
    29  	idleDesc               = "The number of idle connections."
    30  	waitCountDesc          = "The total number of connections waited for."
    31  	waitDurationDesc       = "The total time blocked waiting for a new connection."
    32  	maxIdleClosedDesc      = "The total number of connections closed due to SetMaxIdleConns."
    33  	maxIdleTimeClosedDesc  = "The total number of connections closed due to SetConnMaxIdleTime."
    34  	maxLifetimeClosedDesc  = "The total number of connections closed due to SetConnMaxLifetime."
    35  )
    36  
    37  // DBStatsGetter is an interface for sql.DBStats. It's implemented by sql.DB.
    38  type DBStatsGetter interface {
    39  	Stats() sql.DBStats
    40  }
    41  
    42  // DBStatsCollector implements the prometheus.Collector interface.
    43  type DBStatsCollector struct {
    44  	sg DBStatsGetter
    45  
    46  	maxOpenDesc           *prometheus.Desc
    47  	openDesc              *prometheus.Desc
    48  	inUseDesc             *prometheus.Desc
    49  	idleDesc              *prometheus.Desc
    50  	waitCountDesc         *prometheus.Desc
    51  	waitDurationDesc      *prometheus.Desc
    52  	maxIdleClosedDesc     *prometheus.Desc
    53  	maxIdleTimeClosedDesc *prometheus.Desc
    54  	maxLifetimeClosedDesc *prometheus.Desc
    55  }
    56  
    57  // Describe implements the prometheus.Collector interface.
    58  func (c *DBStatsCollector) Describe(ch chan<- *prometheus.Desc) {
    59  	ch <- c.maxOpenDesc
    60  	ch <- c.openDesc
    61  	ch <- c.inUseDesc
    62  	ch <- c.idleDesc
    63  	ch <- c.waitCountDesc
    64  	ch <- c.waitDurationDesc
    65  	ch <- c.maxIdleClosedDesc
    66  	ch <- c.maxIdleTimeClosedDesc
    67  	ch <- c.maxLifetimeClosedDesc
    68  }
    69  
    70  // Collect implements the prometheus.Collector interface.
    71  func (c *DBStatsCollector) Collect(ch chan<- prometheus.Metric) {
    72  	stats := c.sg.Stats()
    73  
    74  	ch <- prometheus.MustNewConstMetric(
    75  		c.maxOpenDesc,
    76  		prometheus.GaugeValue,
    77  		float64(stats.MaxOpenConnections),
    78  	)
    79  	ch <- prometheus.MustNewConstMetric(
    80  		c.openDesc,
    81  		prometheus.GaugeValue,
    82  		float64(stats.OpenConnections),
    83  	)
    84  	ch <- prometheus.MustNewConstMetric(
    85  		c.inUseDesc,
    86  		prometheus.GaugeValue,
    87  		float64(stats.InUse),
    88  	)
    89  	ch <- prometheus.MustNewConstMetric(
    90  		c.idleDesc,
    91  		prometheus.GaugeValue,
    92  		float64(stats.Idle),
    93  	)
    94  	ch <- prometheus.MustNewConstMetric(
    95  		c.waitCountDesc,
    96  		prometheus.CounterValue,
    97  		float64(stats.WaitCount),
    98  	)
    99  	ch <- prometheus.MustNewConstMetric(
   100  		c.waitDurationDesc,
   101  		prometheus.CounterValue,
   102  		stats.WaitDuration.Seconds(),
   103  	)
   104  	ch <- prometheus.MustNewConstMetric(
   105  		c.maxIdleClosedDesc,
   106  		prometheus.CounterValue,
   107  		float64(stats.MaxIdleClosed),
   108  	)
   109  	ch <- prometheus.MustNewConstMetric(
   110  		c.maxIdleTimeClosedDesc,
   111  		prometheus.CounterValue,
   112  		float64(stats.MaxIdleTimeClosed),
   113  	)
   114  	ch <- prometheus.MustNewConstMetric(
   115  		c.maxLifetimeClosedDesc,
   116  		prometheus.CounterValue,
   117  		float64(stats.MaxLifetimeClosed),
   118  	)
   119  }
   120  
   121  type dbStatsCollectorConfig struct {
   122  	extraLabels prometheus.Labels
   123  }
   124  
   125  // DBStatsCollectorOption is used to pass options in NewDBStatsCollector.
   126  type DBStatsCollectorOption func(*dbStatsCollectorConfig)
   127  
   128  // WithExtraLabels will configure extra label values to apply to the DBStats metrics.
   129  // A label named db_name will be ignored, as this is set internally.
   130  func WithExtraLabels(labelValues map[string]string) DBStatsCollectorOption {
   131  	return func(config *dbStatsCollectorConfig) {
   132  		config.extraLabels = labelValues
   133  	}
   134  }
   135  
   136  func applyDBStatsCollectorOptions(opts []DBStatsCollectorOption) dbStatsCollectorConfig {
   137  	config := dbStatsCollectorConfig{}
   138  	for _, v := range opts {
   139  		v(&config)
   140  	}
   141  
   142  	return config
   143  }
   144  
   145  // NewDBStatsCollector creates a new DBStatsCollector.
   146  func NewDBStatsCollector(dbName string, sg DBStatsGetter, opts ...DBStatsCollectorOption) *DBStatsCollector {
   147  	config := applyDBStatsCollectorOptions(opts)
   148  
   149  	if config.extraLabels == nil {
   150  		config.extraLabels = make(prometheus.Labels)
   151  	}
   152  	config.extraLabels[dbNameLabel] = dbName
   153  
   154  	return &DBStatsCollector{
   155  		sg: sg,
   156  		maxOpenDesc: prometheus.NewDesc(
   157  			prometheus.BuildFQName(namespace, subsystem, maxOpenConnectionsName),
   158  			maxOpenConnectionsDesc,
   159  			nil,
   160  			config.extraLabels,
   161  		),
   162  		openDesc: prometheus.NewDesc(
   163  			prometheus.BuildFQName(namespace, subsystem, openConnectionsName),
   164  			openConnectionsDesc,
   165  			nil,
   166  			config.extraLabels,
   167  		),
   168  		inUseDesc: prometheus.NewDesc(
   169  			prometheus.BuildFQName(namespace, subsystem, inUseName),
   170  			inUseDesc,
   171  			nil,
   172  			config.extraLabels,
   173  		),
   174  		idleDesc: prometheus.NewDesc(
   175  			prometheus.BuildFQName(namespace, subsystem, idleName),
   176  			idleDesc,
   177  			nil,
   178  			config.extraLabels,
   179  		),
   180  		waitCountDesc: prometheus.NewDesc(
   181  			prometheus.BuildFQName(namespace, subsystem, waitCountName),
   182  			waitCountDesc,
   183  			nil,
   184  			config.extraLabels,
   185  		),
   186  		waitDurationDesc: prometheus.NewDesc(
   187  			prometheus.BuildFQName(namespace, subsystem, waitDurationName),
   188  			waitDurationDesc,
   189  			nil,
   190  			config.extraLabels,
   191  		),
   192  		maxIdleClosedDesc: prometheus.NewDesc(
   193  			prometheus.BuildFQName(namespace, subsystem, maxIdleClosedName),
   194  			maxIdleClosedDesc,
   195  			nil,
   196  			config.extraLabels,
   197  		),
   198  		maxIdleTimeClosedDesc: prometheus.NewDesc(
   199  			prometheus.BuildFQName(namespace, subsystem, maxIdleTimeClosedName),
   200  			maxIdleTimeClosedDesc,
   201  			nil,
   202  			config.extraLabels,
   203  		),
   204  		maxLifetimeClosedDesc: prometheus.NewDesc(
   205  			prometheus.BuildFQName(namespace, subsystem, maxLifetimeClosedName),
   206  			maxLifetimeClosedDesc,
   207  			nil,
   208  			config.extraLabels,
   209  		),
   210  	}
   211  }