Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func main() {
flag.StringVar(&opts.LogFormat, "log-format", "console", "Define log format. Allowed values: console, json")
flag.BoolVar(&opts.VerifyConfig, "verify-config", false, "Enable this flag to check config file loads, then exit")
flag.BoolVar(&opts.Version, "version", false, "set to print version information")
flag.BoolVar(&opts.EnableAutoReload, "enable-auto-reload", true, "Enable automatic config reload when the config file changes")
flag.Parse()

if opts.Version {
Expand Down Expand Up @@ -126,6 +127,38 @@ func main() {
os.Exit(1)
}

var configWatcher *config.ConfigWatcher
if opts.EnableAutoReload && opts.ConfigFile != "" {
configWatcher, err = config.NewConfigWatcher(logger, opts.ConfigFile, func() {
// Create a new config instance for reloading
newCfg := config.Config{
Listen: config.ListenConfig{
Port: 4040,
MetricsEndpoint: "/metrics",
},
}

if err := config.LoadConfigFromFile(logger, &newCfg, opts.ConfigFile); err != nil {
logger.Errorf("error reloading config: %v", err)
return
}

if stabilityError := newCfg.StabilityWarnings(); stabilityError != nil && !opts.EnableExperimentalFeatures {
logger.Errorf("reloaded config contains experimental features but they are not enabled")
return
}

// Update the current config
cfg = newCfg
logger.Info("configuration reloaded successfully")
})
if err != nil {
logger.Errorf("error setting up config watcher: %v", err)
} else {
defer configWatcher.Close()
}
}

if cfg.Consul.Enable {
setupConsul(logger, &cfg, stopChan, &stopHandlers)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/config/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type StartupFlags struct {
MetricsEndpoint string
VerifyConfig bool
Version bool
EnableAutoReload bool

LogLevel string
LogFormat string
Expand Down
64 changes: 64 additions & 0 deletions pkg/config/watcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package config

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your code does not pass gofmt in 1 place. Go fmt your code!


import (
"github.com/fsnotify/fsnotify"
"github.com/martin-helmich/prometheus-nginxlog-exporter/log"
)

// ConfigWatcher watches a configuration file for changes
type ConfigWatcher struct {
watcher *fsnotify.Watcher
logger *log.Logger
configFile string
onChange func()
}

// NewConfigWatcher creates a new configuration watcher
func NewConfigWatcher(logger *log.Logger, configFile string, onChange func()) (*ConfigWatcher, error) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}

w := &ConfigWatcher{
watcher: watcher,
logger: logger,
configFile: configFile,
onChange: onChange,
}

if err := watcher.Add(configFile); err != nil {
watcher.Close()
return nil, err
}

go w.watch()

return w, nil
}

// watch monitors the config file for changes
func (w *ConfigWatcher) watch() {
for {
select {
case event, ok := <-w.watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Write == fsnotify.Write {
w.logger.Infof("config file changed, triggering reload")
w.onChange()
}
case err, ok := <-w.watcher.Errors:
if !ok {
return
}
w.logger.Errorf("error watching config file: %v", err)
}
}
}

// Close stops watching the configuration file
func (w *ConfigWatcher) Close() error {
return w.watcher.Close()
}