CI / changes (push) Successful in 9s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 26s
CI / web (push) Successful in 33s
CI / go (push) Successful in 2m11s
CI / bird2 (push) Successful in 16s
CI / release (push) Successful in 3m27s
Added PostgreSQL monitoring and maintenance capabilities to the API, including new endpoints for instance-level metrics, maintenance operations, and job scheduling. Updated the HTTP API to support PostgreSQL monitoring routes and integrated a background scheduler for metrics collection. Enhanced the CLI with database commands for maintenance tasks. Updated documentation to reflect these changes.
91 lines
2.0 KiB
Go
91 lines
2.0 KiB
Go
package pgmonitor
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// Service provides PostgreSQL observability and maintenance helpers (control plane instance scope).
|
|
type Service struct {
|
|
pool *pgxpool.Pool
|
|
cache *ttlCache
|
|
}
|
|
|
|
// NewService constructs a metrics service for the API PostgreSQL pool.
|
|
func NewService(pool *pgxpool.Pool) *Service {
|
|
if pool == nil {
|
|
return nil
|
|
}
|
|
return &Service{
|
|
pool: pool,
|
|
cache: newTTLCache(10 * time.Second),
|
|
}
|
|
}
|
|
|
|
// Pool exposes the underlying pool for job workers.
|
|
func (s *Service) Pool() *pgxpool.Pool {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
return s.pool
|
|
}
|
|
|
|
// Overview returns cached instance-level stats.
|
|
func (s *Service) Overview(ctx context.Context) (Overview, error) {
|
|
if s == nil || s.pool == nil {
|
|
return Overview{}, errors.New("pgmonitor: postgres not configured")
|
|
}
|
|
if v, ok := s.cache.get("overview"); ok {
|
|
if o, ok := v.(Overview); ok {
|
|
return o, nil
|
|
}
|
|
}
|
|
o, err := s.fetchOverview(ctx)
|
|
if err != nil {
|
|
return Overview{}, err
|
|
}
|
|
s.cache.set("overview", o)
|
|
return o, nil
|
|
}
|
|
|
|
// Locks returns active / blocking locks.
|
|
func (s *Service) Locks(ctx context.Context) ([]LockRow, error) {
|
|
if s == nil || s.pool == nil {
|
|
return nil, errors.New("pgmonitor: postgres not configured")
|
|
}
|
|
if v, ok := s.cache.get("locks"); ok {
|
|
if rows, ok := v.([]LockRow); ok {
|
|
return rows, nil
|
|
}
|
|
}
|
|
rows, err := queryLocks(ctx, s.pool)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s.cache.set("locks", rows)
|
|
return rows, nil
|
|
}
|
|
|
|
// Tables returns top tables by size with I/O stats.
|
|
func (s *Service) Tables(ctx context.Context, limit int) ([]TableStat, error) {
|
|
if s == nil || s.pool == nil {
|
|
return nil, errors.New("pgmonitor: postgres not configured")
|
|
}
|
|
key := fmt.Sprintf("tables:%d", limit)
|
|
if v, ok := s.cache.get(key); ok {
|
|
if rows, ok := v.([]TableStat); ok {
|
|
return rows, nil
|
|
}
|
|
}
|
|
rows, err := queryTables(ctx, s.pool, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s.cache.set(key, rows)
|
|
return rows, nil
|
|
}
|