Skip to content

Commit 4dc3102

Browse files
committed
Support for collecting and reporting PgBouncer metrics
1 parent 0973182 commit 4dc3102

5 files changed

Lines changed: 496 additions & 26 deletions

File tree

cmd/pgmetrics/report.go

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,19 @@ import (
2424
"strings"
2525
"time"
2626

27-
"github.com/dustin/go-humanize"
27+
humanize "github.com/dustin/go-humanize"
2828
"github.com/rapidloop/pgmetrics"
2929
)
3030

3131
func writeHumanTo(fd io.Writer, o options, result *pgmetrics.Model) {
32+
if result.PgBouncer != nil {
33+
pgbouncerWriteHumanTo(fd, o, result)
34+
} else {
35+
postgresWriteHumanTo(fd, o, result)
36+
}
37+
}
38+
39+
func postgresWriteHumanTo(fd io.Writer, o options, result *pgmetrics.Model) {
3240
version := getVersion(result)
3341
sincePrior, _ := lsnDiff(result.RedoLSN, result.PriorLSN)
3442
sinceRedo, _ := lsnDiff(result.CheckpointLSN, result.RedoLSN)
@@ -1270,6 +1278,108 @@ System Information:
12701278
tw.write(fd, " ")
12711279
}
12721280

1281+
//------------------------------------------------------------------------------
1282+
// pgbouncer
1283+
1284+
func pgbouncerWriteHumanTo(fd io.Writer, o options, result *pgmetrics.Model) {
1285+
var tw tableWriter
1286+
fmt.Fprintf(fd, `
1287+
pgmetrics run at: %s
1288+
`,
1289+
fmtTimeAndSince(result.Metadata.At),
1290+
)
1291+
1292+
// databases
1293+
fmt.Fprintf(fd, `
1294+
PgBouncer Databases:
1295+
`)
1296+
tw.clear()
1297+
tw.add("Database", "Maps To", "Paused?", "Disabled?", "Clients", "Xacts*", "Queries*", "Client Wait*")
1298+
var dbs []string
1299+
for _, db := range result.PgBouncer.Databases {
1300+
dbs = append(dbs, db.Database)
1301+
}
1302+
sort.Strings(dbs)
1303+
for _, name := range dbs {
1304+
cols := []interface{}{name}
1305+
for _, db := range result.PgBouncer.Databases {
1306+
if db.Database == name {
1307+
if name == "pgbouncer" {
1308+
cols = append(cols, "(internal)")
1309+
} else {
1310+
host := db.Host
1311+
if strings.Index(host, ":") >= 0 {
1312+
host = "[" + host + "]"
1313+
}
1314+
user := db.User
1315+
if len(user) > 0 {
1316+
user += "@"
1317+
}
1318+
cols = append(cols, fmt.Sprintf("%s%s:%d/%s", user, host, db.Port, db.SourceDatabase))
1319+
}
1320+
cols = append(cols, fmtYesNo(db.Paused), fmtYesNo(db.Disabled))
1321+
if db.MaxConn != 0 {
1322+
cols = append(cols, fmt.Sprintf("%d of %d", db.CurrConn, db.MaxConn))
1323+
} else {
1324+
cols = append(cols, db.CurrConn)
1325+
}
1326+
break
1327+
}
1328+
}
1329+
found := false
1330+
for _, s := range result.PgBouncer.Stats {
1331+
if s.Database == name {
1332+
cols = append(cols,
1333+
s.TotalXactCount,
1334+
s.TotalQueryCount,
1335+
time.Duration(s.TotalWaitTime*1e9).Truncate(time.Millisecond))
1336+
found = true
1337+
break
1338+
}
1339+
}
1340+
if !found {
1341+
cols = append(cols, "0", "0", "0s")
1342+
}
1343+
tw.add(cols...)
1344+
}
1345+
w := tw.write(fd, " ")
1346+
msg := "* = cumulative values since start of PgBouncer"
1347+
fmt.Fprintf(fd, `%*s
1348+
`,
1349+
w, msg)
1350+
1351+
// pools
1352+
fmt.Fprintf(fd, `
1353+
PgBouncer Pools:
1354+
`)
1355+
tw.clear()
1356+
tw.add("User", "Database", "Mode", "Client Conns", "Server Conns", "Max Wait")
1357+
for _, p := range result.PgBouncer.Pools {
1358+
tw.add(
1359+
p.UserName,
1360+
p.Database,
1361+
p.Mode,
1362+
fmt.Sprintf("%d actv, %d wtng", p.ClActive, p.ClWaiting),
1363+
fmt.Sprintf("%d actv, %d idle, %d othr", p.SvActive, p.SvIdle, p.SvUsed+p.SvTested),
1364+
time.Duration(p.MaxWait*1e9).Truncate(time.Millisecond))
1365+
}
1366+
tw.write(fd, " ")
1367+
1368+
// client connections
1369+
r := result.PgBouncer
1370+
fmt.Fprintf(fd, `
1371+
Current Connections:
1372+
Clients: %d active, %d waiting, %d idle, %d used
1373+
Servers: %d active, %d idle, %d used
1374+
Client Wait Times: max %v, avg %v
1375+
1376+
`,
1377+
r.CCActive, r.CCWaiting, r.CCIdle, r.CCUsed,
1378+
r.SCActive, r.SCIdle, r.SCUsed,
1379+
time.Duration(r.CCMaxWait*1e9).Truncate(time.Millisecond),
1380+
time.Duration(r.CCAvgWait*1e9).Truncate(time.Millisecond))
1381+
}
1382+
12731383
//------------------------------------------------------------------------------
12741384

12751385
func fmtTime(at int64) string {
@@ -1494,7 +1604,7 @@ func (t *tableWriter) cols() int {
14941604
return n
14951605
}
14961606

1497-
func (t *tableWriter) write(fd io.Writer, pfx string) {
1607+
func (t *tableWriter) write(fd io.Writer, pfx string) (tw int) {
14981608
if len(t.data) == 0 {
14991609
return
15001610
}
@@ -1512,6 +1622,11 @@ func (t *tableWriter) write(fd io.Writer, pfx string) {
15121622
}
15131623
}
15141624
}
1625+
// calculate total width
1626+
tw = len(pfx) + 1 // "prefix", "|"
1627+
for _, w := range widths {
1628+
tw += 1 + w + 1 + 1 // blank, "value", blank, "|"
1629+
}
15151630
// print line
15161631
line := func() {
15171632
fmt.Fprintf(fd, "%s+", pfx)
@@ -1533,4 +1648,5 @@ func (t *tableWriter) write(fd io.Writer, pfx string) {
15331648
fmt.Fprintln(fd)
15341649
}
15351650
line()
1651+
return
15361652
}

0 commit comments

Comments
 (0)