|
5 | 5 | "fmt" |
6 | 6 | "net/http" |
7 | 7 | "os" |
| 8 | + "os/signal" |
8 | 9 | "runtime" |
| 10 | + "syscall" |
9 | 11 | "time" |
10 | 12 |
|
11 | 13 | "github.com/burningalchemist/sql_exporter" |
@@ -98,94 +100,43 @@ func main() { |
98 | 100 | http.Handle(*metricsPath, promhttp.InstrumentMetricHandler(prometheus.DefaultRegisterer, ExporterHandlerFor(exporter))) |
99 | 101 | // Expose exporter metrics separately, for debugging purposes. |
100 | 102 | http.Handle("/sql_exporter_metrics", promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})) |
101 | | - |
102 | | - // Expose refresh handler to reload query collections |
| 103 | + // Expose refresh handler to reload collectors and targets |
103 | 104 | if *enableReload { |
104 | | - http.HandleFunc("/reload", reloadCollectors(exporter)) |
| 105 | + http.HandleFunc("/reload", reloadHandler(exporter)) |
105 | 106 | } |
106 | 107 |
|
| 108 | + // Handle SIGHUP for reloading the configuration |
| 109 | + go func() { |
| 110 | + c := make(chan os.Signal, 1) |
| 111 | + signal.Notify(c, syscall.SIGHUP) |
| 112 | + for { |
| 113 | + <-c |
| 114 | + err := sql_exporter.Reload(exporter, configFile) |
| 115 | + if err != nil { |
| 116 | + klog.Error(err) |
| 117 | + continue |
| 118 | + } |
| 119 | + } |
| 120 | + }() |
| 121 | + |
| 122 | + // Start the web server |
107 | 123 | server := &http.Server{Addr: *listenAddress, ReadHeaderTimeout: httpReadHeaderTimeout} |
108 | | - if err := web.ListenAndServe(server, &web.FlagConfig{WebListenAddresses: &([]string{*listenAddress}), |
109 | | - WebConfigFile: webConfigFile, WebSystemdSocket: OfBool(false)}, logger); err != nil { |
| 124 | + if err := web.ListenAndServe(server, &web.FlagConfig{ |
| 125 | + WebListenAddresses: &([]string{*listenAddress}), |
| 126 | + WebConfigFile: webConfigFile, WebSystemdSocket: OfBool(false), |
| 127 | + }, logger); err != nil { |
110 | 128 | klog.Fatal(err) |
111 | 129 | } |
112 | 130 | } |
113 | 131 |
|
114 | | -func reloadCollectors(e sql_exporter.Exporter) func(http.ResponseWriter, *http.Request) { |
| 132 | +// reloadHandler returns a handler that reloads collectors and targets |
| 133 | +func reloadHandler(e sql_exporter.Exporter) func(http.ResponseWriter, *http.Request) { |
115 | 134 | return func(w http.ResponseWriter, r *http.Request) { |
116 | | - klog.Warning("Reloading collectors has started...") |
117 | | - klog.Warning("Connections will not be changed upon the restart of the exporter") |
118 | | - exporterNewConfig, err := cfg.Load(*configFile) |
| 135 | + err := sql_exporter.Reload(e, configFile) |
119 | 136 | if err != nil { |
120 | | - klog.Errorf("Error reading config file - %v", err) |
121 | 137 | http.Error(w, err.Error(), http.StatusInternalServerError) |
122 | 138 | return |
123 | 139 | } |
124 | | - currentConfig := e.Config() |
125 | | - klog.Infof("Total collector size change: %v -> %v", len(currentConfig.Collectors), |
126 | | - len(exporterNewConfig.Collectors)) |
127 | | - |
128 | | - if len(currentConfig.Collectors) > 0 { |
129 | | - currentConfig.Collectors = currentConfig.Collectors[:0] |
130 | | - } |
131 | | - currentConfig.Collectors = exporterNewConfig.Collectors |
132 | | - |
133 | | - // Reload Collectors for a single target if there is one |
134 | | - if currentConfig.Target != nil { |
135 | | - klog.Warning("Reloading target collectors...") |
136 | | - // FIXME: Should be t.Collectors() instead of config.Collectors |
137 | | - target, err := sql_exporter.NewTarget("", currentConfig.Target.Name, "", string(currentConfig.Target.DSN), |
138 | | - exporterNewConfig.Target.Collectors(), nil, currentConfig.Globals, currentConfig.Target.EnablePing) |
139 | | - if err != nil { |
140 | | - klog.Errorf("Error recreating a target - %v", err) |
141 | | - http.Error(w, err.Error(), http.StatusInternalServerError) |
142 | | - return |
143 | | - } |
144 | | - e.UpdateTarget([]sql_exporter.Target{target}) |
145 | | - klog.Warning("Collectors have been successfully reloaded for target") |
146 | | - w.WriteHeader(http.StatusOK) |
147 | | - return |
148 | | - } |
149 | | - |
150 | | - // Reload Collectors for Jobs if there are any |
151 | | - if len(currentConfig.Jobs) > 0 { |
152 | | - klog.Warning("Recreating jobs...") |
153 | | - |
154 | | - // We want to preserve `static_configs`` from the previous config revision to avoid any connection changes |
155 | | - for _, currentJob := range currentConfig.Jobs { |
156 | | - for _, newJob := range exporterNewConfig.Jobs { |
157 | | - if newJob.Name == currentJob.Name { |
158 | | - newJob.StaticConfigs = currentJob.StaticConfigs |
159 | | - } |
160 | | - } |
161 | | - } |
162 | | - currentConfig.Jobs = exporterNewConfig.Jobs |
163 | | - |
164 | | - var updateErr error |
165 | | - targets := make([]sql_exporter.Target, 0, len(currentConfig.Jobs)) |
166 | | - |
167 | | - for _, jobConfigItem := range currentConfig.Jobs { |
168 | | - job, err := sql_exporter.NewJob(jobConfigItem, currentConfig.Globals) |
169 | | - if err != nil { |
170 | | - updateErr = err |
171 | | - break |
172 | | - } |
173 | | - targets = append(targets, job.Targets()...) |
174 | | - klog.Infof("Recreated Job: %s", jobConfigItem.Name) |
175 | | - } |
176 | | - |
177 | | - if updateErr != nil { |
178 | | - klog.Errorf("Error recreating jobs - %v", err) |
179 | | - http.Error(w, err.Error(), http.StatusInternalServerError) |
180 | | - return |
181 | | - } |
182 | | - |
183 | | - e.UpdateTarget(targets) |
184 | | - klog.Warning("Query collectors have been successfully reloaded for jobs") |
185 | | - w.WriteHeader(http.StatusOK) |
186 | | - return |
187 | | - } |
188 | | - klog.Warning("No target or jobs have been found - nothing to reload") |
189 | | - http.Error(w, "", http.StatusInternalServerError) |
| 140 | + w.WriteHeader(http.StatusOK) |
190 | 141 | } |
191 | 142 | } |
0 commit comments