lib/promscrape: add -promscrape.configCheckInterval command-line flag for automating config checking

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/431
This commit is contained in:
Aliaksandr Valialkin 2020-04-23 23:40:50 +03:00
parent 83e4c8427e
commit 387a21c96d
3 changed files with 40 additions and 10 deletions

View File

@ -97,16 +97,16 @@ func loadStaticConfigs(path string) ([]StaticConfig, error) {
} }
// loadConfig loads Prometheus config from the given path. // loadConfig loads Prometheus config from the given path.
func loadConfig(path string) (cfg *Config, err error) { func loadConfig(path string) (cfg *Config, data []byte, err error) {
data, err := ioutil.ReadFile(path) data, err = ioutil.ReadFile(path)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot read Prometheus config from %q: %s", path, err) return nil, nil, fmt.Errorf("cannot read Prometheus config from %q: %s", path, err)
} }
var cfgObj Config var cfgObj Config
if err := cfgObj.parse(data, path); err != nil { if err := cfgObj.parse(data, path); err != nil {
return nil, fmt.Errorf("cannot parse Prometheus config from %q: %s", path, err) return nil, nil, fmt.Errorf("cannot parse Prometheus config from %q: %s", path, err)
} }
return &cfgObj, nil return &cfgObj, data, nil
} }
func (cfg *Config) parse(data []byte, path string) error { func (cfg *Config) parse(data []byte, path string) error {

View File

@ -42,7 +42,7 @@ func TestLoadStaticConfigs(t *testing.T) {
} }
func TestLoadConfig(t *testing.T) { func TestLoadConfig(t *testing.T) {
cfg, err := loadConfig("testdata/prometheus.yml") cfg, _, err := loadConfig("testdata/prometheus.yml")
if err != nil { if err != nil {
t.Fatalf("unexpected error: %s", err) t.Fatalf("unexpected error: %s", err)
} }
@ -51,7 +51,7 @@ func TestLoadConfig(t *testing.T) {
} }
// Try loading non-existing file // Try loading non-existing file
cfg, err = loadConfig("testdata/non-existing-file") cfg, _, err = loadConfig("testdata/non-existing-file")
if err == nil { if err == nil {
t.Fatalf("expecting non-nil error") t.Fatalf("expecting non-nil error")
} }
@ -60,7 +60,7 @@ func TestLoadConfig(t *testing.T) {
} }
// Try loading invalid file // Try loading invalid file
cfg, err = loadConfig("testdata/file_sd_1.yml") cfg, _, err = loadConfig("testdata/file_sd_1.yml")
if err == nil { if err == nil {
t.Fatalf("expecting non-nil error") t.Fatalf("expecting non-nil error")
} }

View File

@ -1,6 +1,7 @@
package promscrape package promscrape
import ( import (
"bytes"
"flag" "flag"
"os" "os"
"os/signal" "os/signal"
@ -14,6 +15,8 @@ import (
) )
var ( var (
configCheckInterval = flag.Duration("promscrape.configCheckInterval", 0, "Interval for checking for changes in '-promscrape.config' file. "+
"By default the checking is disabled. Send SIGHUP signal in order to force config check for changes")
fileSDCheckInterval = flag.Duration("promscrape.fileSDCheckInterval", 30*time.Second, "Interval for checking for changes in 'file_sd_config'. "+ fileSDCheckInterval = flag.Duration("promscrape.fileSDCheckInterval", 30*time.Second, "Interval for checking for changes in 'file_sd_config'. "+
"See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#file_sd_config") "See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#file_sd_config")
kubernetesSDCheckInterval = flag.Duration("promscrape.kubernetesSDCheckInterval", 30*time.Second, "Interval for checking for changes in Kubernetes API server. "+ kubernetesSDCheckInterval = flag.Duration("promscrape.kubernetesSDCheckInterval", 30*time.Second, "Interval for checking for changes in Kubernetes API server. "+
@ -55,11 +58,18 @@ func runScraper(configFile string, pushData func(wr *prompbmarshal.WriteRequest)
signal.Notify(sighupCh, syscall.SIGHUP) signal.Notify(sighupCh, syscall.SIGHUP)
logger.Infof("reading Prometheus configs from %q", configFile) logger.Infof("reading Prometheus configs from %q", configFile)
cfg, err := loadConfig(configFile) cfg, data, err := loadConfig(configFile)
if err != nil { if err != nil {
logger.Fatalf("cannot read %q: %s", configFile, err) logger.Fatalf("cannot read %q: %s", configFile, err)
} }
var tickerCh <-chan time.Time
if *configCheckInterval > 0 {
ticker := time.NewTicker(*configCheckInterval)
tickerCh = ticker.C
defer ticker.Stop()
}
mustStop := false mustStop := false
for !mustStop { for !mustStop {
stopCh := make(chan struct{}) stopCh := make(chan struct{})
@ -84,16 +94,36 @@ func runScraper(configFile string, pushData func(wr *prompbmarshal.WriteRequest)
select { select {
case <-sighupCh: case <-sighupCh:
logger.Infof("SIGHUP received; reloading Prometheus configs from %q", configFile) logger.Infof("SIGHUP received; reloading Prometheus configs from %q", configFile)
cfgNew, err := loadConfig(configFile) cfgNew, dataNew, err := loadConfig(configFile)
if err != nil {
logger.Errorf("cannot read %q on SIGHUP: %s; continuing with the previous config", configFile, err)
goto waitForChans
}
if bytes.Equal(data, dataNew) {
logger.Infof("nothing changed in %q", configFile)
goto waitForChans
}
cfg = cfgNew
data = dataNew
case <-tickerCh:
cfgNew, dataNew, err := loadConfig(configFile)
if err != nil { if err != nil {
logger.Errorf("cannot read %q: %s; continuing with the previous config", configFile, err) logger.Errorf("cannot read %q: %s; continuing with the previous config", configFile, err)
goto waitForChans goto waitForChans
} }
if bytes.Equal(data, dataNew) {
// Nothing changed since the previous loadConfig
goto waitForChans
}
cfg = cfgNew cfg = cfgNew
data = dataNew
case <-globalStopCh: case <-globalStopCh:
mustStop = true mustStop = true
} }
if !mustStop {
logger.Infof("found changes in %q; applying these changes", configFile)
}
logger.Infof("stopping Prometheus scrapers") logger.Infof("stopping Prometheus scrapers")
startTime := time.Now() startTime := time.Now()
close(stopCh) close(stopCh)