feat(agent) multi-driver db monitoring, hot-plug config, release pipeline
This commit is contained in:
78
internal/collectors/redis/redis.go
Normal file
78
internal/collectors/redis/redis.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
|
||||
"bugs.watch/agent/internal/aggregate"
|
||||
)
|
||||
|
||||
// Collector queries Redis INFO each sample interval.
|
||||
// All queries run under a 3-second timeout; any failure is silently skipped.
|
||||
// Metrics mapping:
|
||||
// db_conn_pct → used_memory / maxmemory * 100 (skipped when maxmemory=0)
|
||||
// db_threads_running → connected_clients
|
||||
// db_size_bytes → used_memory
|
||||
type Collector struct {
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func New(addr string) (*Collector, error) {
|
||||
opts, err := redis.ParseURL(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.DialTimeout = 3 * time.Second
|
||||
opts.ReadTimeout = 3 * time.Second
|
||||
opts.WriteTimeout = 3 * time.Second
|
||||
return &Collector{client: redis.NewClient(opts)}, nil
|
||||
}
|
||||
|
||||
func (c *Collector) Name() string { return "redis" }
|
||||
|
||||
func (c *Collector) Close() { c.client.Close() }
|
||||
|
||||
func (c *Collector) Collect(window *aggregate.Window) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
info, err := c.client.Info(ctx, "memory", "clients").Result()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fields := parseInfo(info)
|
||||
|
||||
usedMem, _ := strconv.ParseUint(fields["used_memory"], 10, 64)
|
||||
maxMem, _ := strconv.ParseUint(fields["maxmemory"], 10, 64)
|
||||
clients, _ := strconv.ParseUint(fields["connected_clients"], 10, 64)
|
||||
|
||||
if usedMem > 0 {
|
||||
window.SetDBSizeBytes(usedMem)
|
||||
}
|
||||
if clients > 0 {
|
||||
window.AddDBThreadsRunning(float64(clients))
|
||||
}
|
||||
if maxMem > 0 && usedMem > 0 {
|
||||
window.AddDBConnPct(float64(usedMem) / float64(maxMem) * 100)
|
||||
}
|
||||
}
|
||||
|
||||
func parseInfo(s string) map[string]string {
|
||||
out := make(map[string]string)
|
||||
for _, line := range strings.Split(s, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
k, v, ok := strings.Cut(line, ":")
|
||||
if ok {
|
||||
out[strings.TrimSpace(k)] = strings.TrimSpace(v)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user