...

Source file src/github.com/letsencrypt/boulder/sa/metrics.go

Documentation: github.com/letsencrypt/boulder/sa

     1  package sa
     2  
     3  import (
     4  	"database/sql"
     5  
     6  	"github.com/prometheus/client_golang/prometheus"
     7  )
     8  
     9  type dbMetricsCollector struct {
    10  	db         *sql.DB
    11  	dbSettings DbSettings
    12  
    13  	maxOpenConns      *prometheus.Desc
    14  	maxIdleConns      *prometheus.Desc
    15  	connMaxLifetime   *prometheus.Desc
    16  	connMaxIdleTime   *prometheus.Desc
    17  	openConns         *prometheus.Desc
    18  	inUse             *prometheus.Desc
    19  	idle              *prometheus.Desc
    20  	waitCount         *prometheus.Desc
    21  	waitDuration      *prometheus.Desc
    22  	maxIdleClosed     *prometheus.Desc
    23  	maxLifetimeClosed *prometheus.Desc
    24  }
    25  
    26  // Describe is implemented with DescribeByCollect. That's possible because the
    27  // Collect method will always return the same metrics with the same descriptors.
    28  func (dbc dbMetricsCollector) Describe(ch chan<- *prometheus.Desc) {
    29  	prometheus.DescribeByCollect(dbc, ch)
    30  }
    31  
    32  // Collect first triggers the dbMaps's sql.Db's Stats function. Then it
    33  // creates constant metrics for each DBStats value on the fly based on the
    34  // returned data.
    35  //
    36  // Note that Collect could be called concurrently, so we depend on
    37  // Stats() to be concurrency-safe.
    38  func (dbc dbMetricsCollector) Collect(ch chan<- prometheus.Metric) {
    39  	writeStat := func(stat *prometheus.Desc, typ prometheus.ValueType, val float64) {
    40  		ch <- prometheus.MustNewConstMetric(stat, typ, val)
    41  	}
    42  	writeCounter := func(stat *prometheus.Desc, val float64) {
    43  		writeStat(stat, prometheus.CounterValue, val)
    44  	}
    45  	writeGauge := func(stat *prometheus.Desc, val float64) {
    46  		writeStat(stat, prometheus.GaugeValue, val)
    47  	}
    48  
    49  	// Translate the DBMap's db.DBStats counter values into Prometheus metrics.
    50  	dbMapStats := dbc.db.Stats()
    51  	writeGauge(dbc.maxOpenConns, float64(dbMapStats.MaxOpenConnections))
    52  	writeGauge(dbc.maxIdleConns, float64(dbc.dbSettings.MaxIdleConns))
    53  	writeGauge(dbc.connMaxLifetime, float64(dbc.dbSettings.ConnMaxLifetime))
    54  	writeGauge(dbc.connMaxIdleTime, float64(dbc.dbSettings.ConnMaxIdleTime))
    55  	writeGauge(dbc.openConns, float64(dbMapStats.OpenConnections))
    56  	writeGauge(dbc.inUse, float64(dbMapStats.InUse))
    57  	writeGauge(dbc.idle, float64(dbMapStats.Idle))
    58  	writeCounter(dbc.waitCount, float64(dbMapStats.WaitCount))
    59  	writeCounter(dbc.waitDuration, dbMapStats.WaitDuration.Seconds())
    60  	writeCounter(dbc.maxIdleClosed, float64(dbMapStats.MaxIdleClosed))
    61  	writeCounter(dbc.maxLifetimeClosed, float64(dbMapStats.MaxLifetimeClosed))
    62  }
    63  
    64  // initDBMetrics will register a Collector that translates the provided dbMap's
    65  // stats and DbSettings into Prometheus metrics on the fly. The exported metrics
    66  // all start with `db_`. The underlying data comes from sql.DBStats:
    67  // https://pkg.go.dev/database/sql#DBStats
    68  func initDBMetrics(db *sql.DB, stats prometheus.Registerer, dbSettings DbSettings, address string, user string) error {
    69  	// Create a dbMetricsCollector and register it
    70  	dbc := dbMetricsCollector{db: db, dbSettings: dbSettings}
    71  
    72  	labels := prometheus.Labels{"address": address, "user": user}
    73  
    74  	dbc.maxOpenConns = prometheus.NewDesc(
    75  		"db_max_open_connections",
    76  		"Maximum number of DB connections allowed.",
    77  		nil, labels)
    78  
    79  	dbc.maxIdleConns = prometheus.NewDesc(
    80  		"db_max_idle_connections",
    81  		"Maximum number of idle DB connections allowed.",
    82  		nil, labels)
    83  
    84  	dbc.connMaxLifetime = prometheus.NewDesc(
    85  		"db_connection_max_lifetime",
    86  		"Maximum lifetime of DB connections allowed.",
    87  		nil, labels)
    88  
    89  	dbc.connMaxIdleTime = prometheus.NewDesc(
    90  		"db_connection_max_idle_time",
    91  		"Maximum lifetime of idle DB connections allowed.",
    92  		nil, labels)
    93  
    94  	dbc.openConns = prometheus.NewDesc(
    95  		"db_open_connections",
    96  		"Number of established DB connections (in-use and idle).",
    97  		nil, labels)
    98  
    99  	dbc.inUse = prometheus.NewDesc(
   100  		"db_inuse",
   101  		"Number of DB connections currently in use.",
   102  		nil, labels)
   103  
   104  	dbc.idle = prometheus.NewDesc(
   105  		"db_idle",
   106  		"Number of idle DB connections.",
   107  		nil, labels)
   108  
   109  	dbc.waitCount = prometheus.NewDesc(
   110  		"db_wait_count",
   111  		"Total number of DB connections waited for.",
   112  		nil, labels)
   113  
   114  	dbc.waitDuration = prometheus.NewDesc(
   115  		"db_wait_duration_seconds",
   116  		"The total time blocked waiting for a new connection.",
   117  		nil, labels)
   118  
   119  	dbc.maxIdleClosed = prometheus.NewDesc(
   120  		"db_max_idle_closed",
   121  		"Total number of connections closed due to SetMaxIdleConns.",
   122  		nil, labels)
   123  
   124  	dbc.maxLifetimeClosed = prometheus.NewDesc(
   125  		"db_max_lifetime_closed",
   126  		"Total number of connections closed due to SetConnMaxLifetime.",
   127  		nil, labels)
   128  
   129  	return stats.Register(dbc)
   130  }
   131  

View as plain text