Files

95 lines
2.3 KiB
Go
Raw Permalink Normal View History

package mongodb
import (
"context"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"bugs.watch/agent/internal/aggregate"
)
// Collector queries MongoDB serverStatus and listDatabases each sample interval.
// All queries run under a 3-second timeout; any failure is silently skipped.
// Metrics mapping:
// db_conn_pct → current / (current + available) * 100
// db_threads_running → connections.current
// db_size_bytes → totalSize from listDatabases
type Collector struct {
client *mongo.Client
}
func New(uri string) (*Collector, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri).
SetConnectTimeout(3*time.Second).
SetServerSelectionTimeout(3*time.Second))
if err != nil {
return nil, err
}
return &Collector{client: client}, nil
}
func (c *Collector) Name() string { return "mongodb" }
func (c *Collector) Close() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
c.client.Disconnect(ctx)
}
func (c *Collector) Collect(window *aggregate.Window) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
admin := c.client.Database("admin")
var status bson.M
if err := admin.RunCommand(ctx, bson.D{
{Key: "serverStatus", Value: 1},
{Key: "repl", Value: 0},
{Key: "metrics", Value: 0},
{Key: "locks", Value: 0},
}).Decode(&status); err != nil {
return
}
if conns, ok := status["connections"].(bson.M); ok {
current := toFloat64(conns["current"])
available := toFloat64(conns["available"])
total := current + available
if total > 0 {
window.AddDBConnPct(current / total * 100)
}
if current > 0 {
window.AddDBThreadsRunning(current)
}
}
var listResult bson.M
if err := admin.RunCommand(ctx, bson.D{
{Key: "listDatabases", Value: 1},
{Key: "nameOnly", Value: false},
}).Decode(&listResult); err == nil {
if totalSize := toFloat64(listResult["totalSize"]); totalSize > 0 {
window.SetDBSizeBytes(uint64(totalSize))
}
}
}
func toFloat64(v interface{}) float64 {
switch x := v.(type) {
case int32:
return float64(x)
case int64:
return float64(x)
case float64:
return x
}
return 0
}