プラットフォームチームの菅原です。
Goでデータベースを使う場合には、以下のメソッドでコネクションプーリングまわりの設定を調整することが多いと思います。
MaxOpenConnsを設定してアプリケーションからの接続がデータベースのリミットを超えないようにしたり、MaxIdleConnsを設定してアイドルコネクションを保持し接続が都度発生しないようにしたりしますが、サービスにデプロイされた後はその設定が正しいか調べるためメトリクスが必要になります。
func (db *DB) Stats()はそれらコネクションプーリングの統計データを返すメソッドで、以下のような構造体を返します。
type DBStats struct { MaxOpenConnections int // Maximum number of open connections to the database. // Pool Status OpenConnections int // The number of established connections both in use and idle. InUse int // The number of connections currently in use. Idle int // The number of idle connections. // Counters WaitCount int64 // The total number of connections waited for. WaitDuration time.Duration // The total time blocked waiting for a new connection. MaxIdleClosed int64 // The total number of connections closed due to SetMaxIdleConns. MaxIdleTimeClosed int64 // The total number of connections closed due to SetConnMaxIdleTime. MaxLifetimeClosed int64 // The total number of connections closed due to SetConnMaxLifetime. }
カンムのサービスではモニタリング・ログ収集にDatadog、Goアプリからのログ出力にzerologを使っているので、アプリ起動時に以下のようなgoroutineを実行してコネクションプーリングの統計データをログ出力するようにしてみました。
// goroutine func LogDBStats(db *sql.DB, host string, interval time.Duration, logger *zerolog.Logger) func() { ticker := time.NewTicker(interval) done := make(chan struct{}) go func() { for { select { case <-done: return case <-ticker.C: logger.Info(). Str("log_type", "db_stats"). Str("host", host). Interface("db_stats", db.Stats()). Msg("Database statistics") } } }() return func() { ticker.Stop() close(done) } }
// アプリ側 if cfg.DBStatsIntervalSec > 0 { interval := time.Duration(cfg.DBStatsIntervalSec) * time.Second cleanup := utils.LogDBStats(db, cfg.DBHost, interval, &logger) defer cleanup() }
こうするとDatadogのログ管理でコネクションプーリングの統計データを見られるようになります。

またログの属性値からグラフを作成することも可能です。

これでコネクションプーリングまわりをモニタリングできるようになって便利になりました…
…と、思っていたのですが、dd-trace-goを調べてみたらv1.63.0でDB Statsを収集するための変更が入っていました。
なのでcontrib/database/sqlのsqltrace.Open()/OpenDB()を使っている場合、WithDBStats()を使えば普通にメトリクスを収集することができます。
db := sqltrace.OpenDB(connector, sqltrace.WithServiceName("my-service"), sqltrace.WithDBStats())

Datadogのログ管理でメトリクスを収集する場合、メトリクスの保持期間がログの保持期間と同じなってしまうので、長期的にメトリクスを保持したい場合はWithDBStats()を使った方が良さそうです。