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 }