Add cron schedules and sync docs
Some checks failed
ci / openapi (push) Failing after 7s
ci / agent (push) Failing after 5s
ci / server (push) Failing after 6s
ci / stack-smoke (push) Has been skipped
ci / web (push) Failing after 5s

This commit is contained in:
Stanislav Rossovskii
2026-06-23 19:18:01 +04:00
parent f5ec97fcb9
commit d6f9335398
24 changed files with 638 additions and 131 deletions

View File

@@ -47,9 +47,7 @@ func (a *App) Run(ctx context.Context) error {
a.Metrics.ConfigLoadSuccess.Set(1)
a.Metrics.ChecksConfigured.Set(float64(len(cfg.Checks)))
a.Metrics.BuildInfo.WithLabelValues(a.Version, boolLabel(cfg.PushesToServer()), boolLabel(cfg.ExposesMetrics())).Set(1)
for _, c := range cfg.Checks {
a.Metrics.CheckInterval.WithLabelValues(c.ID).Set(c.Interval.Duration.Seconds())
}
a.recordCheckScheduleMetrics(cfg.Checks)
var wg sync.WaitGroup
@@ -256,9 +254,7 @@ func (a *App) Reload(newCfg *config.Config, newAgentID string) error {
a.Metrics.ConfigReloadTotal.WithLabelValues("success").Inc()
a.Metrics.ConfigLastReloadSuccess.Set(float64(time.Now().Unix()))
a.Metrics.ChecksConfigured.Set(float64(len(newCfg.Checks)))
for _, c := range newCfg.Checks {
a.Metrics.CheckInterval.WithLabelValues(c.ID).Set(c.Interval.Duration.Seconds())
}
a.recordCheckScheduleMetrics(newCfg.Checks)
a.schedulerMu.RLock()
mgr := a.scheduler
@@ -275,6 +271,16 @@ func (a *App) RecordReloadFailure() {
a.Metrics.ConfigReloadTotal.WithLabelValues("failure").Inc()
}
func (a *App) recordCheckScheduleMetrics(checks []config.CheckConfig) {
for _, c := range checks {
if c.UsesInterval() {
a.Metrics.CheckInterval.WithLabelValues(c.ID).Set(c.Interval.Duration.Seconds())
} else {
a.Metrics.CheckInterval.DeleteLabelValues(c.ID)
}
}
}
func (a *App) config() *config.Config {
a.cfgMu.RLock()
defer a.cfgMu.RUnlock()

View File

@@ -17,6 +17,7 @@ import (
"github.com/monlet/agent/internal/config"
"github.com/monlet/agent/internal/metrics"
"github.com/monlet/agent/internal/spool"
dto "github.com/prometheus/client_model/go"
)
func TestPrometheusOnlyDoesNotPush(t *testing.T) {
@@ -257,6 +258,92 @@ func TestReloadAcceptsLabelsAndChecks(t *testing.T) {
}
}
func TestReloadUpdatesIntervalMetricForCron(t *testing.T) {
oldCfg := &config.Config{
AgentID: "a1",
Hostname: "h",
StateDir: "/tmp/old",
Server: config.ServerConfig{
Enabled: boolPtr(true),
URL: "http://server",
HeartbeatInterval: config.Duration{Duration: 10 * time.Second},
BatchInterval: config.Duration{Duration: 10 * time.Second},
},
Metrics: config.MetricsConfig{Enabled: false},
Checks: []config.CheckConfig{{
ID: "c1",
Command: "true",
Interval: config.Duration{Duration: time.Second},
Timeout: config.Duration{Duration: time.Second},
}},
}
a := &App{
Cfg: oldCfg,
AgentID: "a1",
Metrics: metrics.New(),
}
a.recordCheckScheduleMetrics(oldCfg.Checks)
if got, ok := checkIntervalMetric(t, a, "c1"); !ok || got != 1 {
t.Fatalf("interval metric missing before reload: value=%v ok=%v", got, ok)
}
cronCfg := *oldCfg
cronCfg.Checks = []config.CheckConfig{{
ID: "c1",
Command: "true",
Cron: "0 * * * *",
Timeout: config.Duration{Duration: time.Second},
}}
if err := a.Reload(&cronCfg, "a1"); err != nil {
t.Fatal(err)
}
if got, ok := checkIntervalMetric(t, a, "c1"); ok {
t.Fatalf("interval metric must be deleted for cron check, got %v", got)
}
intervalCfg := cronCfg
intervalCfg.Checks = []config.CheckConfig{{
ID: "c1",
Command: "true",
Interval: config.Duration{Duration: 2 * time.Second},
Timeout: config.Duration{Duration: time.Second},
}}
if err := a.Reload(&intervalCfg, "a1"); err != nil {
t.Fatal(err)
}
if got, ok := checkIntervalMetric(t, a, "c1"); !ok || got != 2 {
t.Fatalf("interval metric missing after interval reload: value=%v ok=%v", got, ok)
}
}
func checkIntervalMetric(t *testing.T, a *App, checkID string) (float64, bool) {
t.Helper()
families, err := a.Metrics.Registry.Gather()
if err != nil {
t.Fatal(err)
}
for _, family := range families {
if family.GetName() != "monlet_agent_check_interval_seconds" {
continue
}
for _, metric := range family.GetMetric() {
if labelValue(metric.GetLabel(), "check_id") == checkID && metric.GetGauge() != nil {
return metric.GetGauge().GetValue(), true
}
}
}
return 0, false
}
func labelValue(labels []*dto.LabelPair, name string) string {
for _, label := range labels {
if label.GetName() == name {
return label.GetValue()
}
}
return ""
}
func boolPtr(v bool) *bool {
return &v
}