@@ -3,6 +3,7 @@ package main
3
3
import (
4
4
"crypto/tls"
5
5
"flag"
6
+ "fmt"
6
7
"log"
7
8
"net/http"
8
9
"os"
@@ -26,16 +27,16 @@ func getEnv(key, defaultValue string) string {
26
27
return value
27
28
}
28
29
29
- func getEnvInt (key string , defaultValue int ) int {
30
+ func getEnvUint (key string , defaultValue uint ) uint {
30
31
value , ok := os .LookupEnv (key )
31
32
if ! ok {
32
33
return defaultValue
33
34
}
34
- i , err := strconv .ParseInt (value , 10 , 64 )
35
+ i , err := strconv .ParseUint (value , 10 , 64 )
35
36
if err != nil {
36
- log .Fatalf ("Environment variable value for %s must be an int : %v" , key , err )
37
+ log .Fatalf ("Environment variable value for %s must be an uint : %v" , key , err )
37
38
}
38
- return int (i )
39
+ return uint (i )
39
40
}
40
41
41
42
func getEnvBool (key string , defaultValue bool ) bool {
@@ -50,23 +51,53 @@ func getEnvBool(key string, defaultValue bool) bool {
50
51
return b
51
52
}
52
53
53
- func getEnvDuration (key string , defaultValue time.Duration ) time. Duration {
54
+ func getEnvPositiveDuration (key string , defaultValue time.Duration ) positiveDuration {
54
55
value , ok := os .LookupEnv (key )
55
56
if ! ok {
56
- return defaultValue
57
+ return positiveDuration { defaultValue }
57
58
}
58
- d , err := time .ParseDuration (value )
59
+
60
+ posDur , err := parsePositiveDuration (value )
59
61
if err != nil {
60
- log .Fatalf ("Environment variable value for %s must be a duration: %v" , key , err )
62
+ log .Fatalf ("Environment variable value for %s must be a positive duration: %v" , key , err )
61
63
}
62
- return d
64
+ return posDur
63
65
}
64
66
65
- func createClientWithRetries (getClient func () (interface {}, error ), retries int , retryInterval time.Duration ) (interface {}, error ) {
67
+ // positiveDuration is a wrapper of time.Duration to ensure only positive values are accepted
68
+ type positiveDuration struct { time.Duration }
69
+
70
+ func (pd * positiveDuration ) Set (s string ) error {
71
+ dur , err := parsePositiveDuration (s )
72
+ if err != nil {
73
+ return err
74
+ }
75
+
76
+ pd .Duration = dur .Duration
77
+ return nil
78
+ }
79
+
80
+ func parsePositiveDuration (s string ) (positiveDuration , error ) {
81
+ dur , err := time .ParseDuration (s )
82
+ if err != nil {
83
+ return positiveDuration {}, err
84
+ }
85
+ if dur < 0 {
86
+ return positiveDuration {}, fmt .Errorf ("negative duration %v is not valid" , dur )
87
+ }
88
+ return positiveDuration {dur }, nil
89
+ }
90
+
91
+ func createPositiveDurationFlag (name string , value positiveDuration , usage string ) * positiveDuration {
92
+ flag .Var (& value , name , usage )
93
+ return & value
94
+ }
95
+
96
+ func createClientWithRetries (getClient func () (interface {}, error ), retries uint , retryInterval time.Duration ) (interface {}, error ) {
66
97
var err error
67
98
var nginxClient interface {}
68
99
69
- for i := retries ; i >= 0 ; i -- {
100
+ for i := 0 ; i <= int ( retries ) ; i ++ {
70
101
nginxClient , err = getClient ()
71
102
if err == nil {
72
103
return nginxClient , nil
90
121
defaultNginxPlus = getEnvBool ("NGINX_PLUS" , false )
91
122
defaultScrapeURI = getEnv ("SCRAPE_URI" , "http://127.0.0.1:8080/stub_status" )
92
123
defaultSslVerify = getEnvBool ("SSL_VERIFY" , true )
93
- defaultTimeout = getEnvDuration ("TIMEOUT" , time .Second * 5 )
94
- defaultNginxRetries = getEnvInt ("NGINX_RETRIES" , 0 )
95
- defaultNginxRetryInterval = getEnvDuration ("NGINX_RETRY_INTERVAL" , time .Second * 5 )
124
+ defaultTimeout = getEnvPositiveDuration ("TIMEOUT" , time .Second * 5 )
125
+ defaultNginxRetries = getEnvUint ("NGINX_RETRIES" , 0 )
126
+ defaultNginxRetryInterval = getEnvPositiveDuration ("NGINX_RETRY_INTERVAL" , time .Second * 5 )
96
127
97
128
// Command-line flags
98
129
listenAddr = flag .String ("web.listen-address" ,
@@ -111,13 +142,16 @@ var (
111
142
sslVerify = flag .Bool ("nginx.ssl-verify" ,
112
143
defaultSslVerify ,
113
144
"Perform SSL certificate verification. The default value can be overwritten by SSL_VERIFY environment variable." )
114
- timeout = flag .Duration ("nginx.timeout" ,
115
- defaultTimeout ,
116
- "A timeout for scraping metrics from NGINX or NGINX Plus. The default value can be overwritten by TIMEOUT environment variable." )
117
- nginxRetries = flag .Int ("nginx.retries" ,
145
+ nginxRetries = flag .Uint ("nginx.retries" ,
118
146
defaultNginxRetries ,
119
147
"A number of retries the exporter will make on start to connect to the NGINX stub_status page/NGINX Plus API before exiting with an error. The default value can be overwritten by NGINX_RETRIES environment variable." )
120
- nginxRetryInterval = flag .Duration ("nginx.retry-interval" ,
148
+
149
+ // Custom command-line flags
150
+ timeout = createPositiveDurationFlag ("nginx.timeout" ,
151
+ defaultTimeout ,
152
+ "A timeout for scraping metrics from NGINX or NGINX Plus. The default value can be overwritten by TIMEOUT environment variable." )
153
+
154
+ nginxRetryInterval = createPositiveDurationFlag ("nginx.retry-interval" ,
121
155
defaultNginxRetryInterval ,
122
156
"An interval between retries to connect to the NGINX stub_status page/NGINX Plus API on start. The default value can be overwritten by NGINX_RETRY_INTERVAL environment variable." )
123
157
)
@@ -144,7 +178,7 @@ func main() {
144
178
registry .MustRegister (buildInfoMetric )
145
179
146
180
httpClient := & http.Client {
147
- Timeout : * timeout ,
181
+ Timeout : timeout . Duration ,
148
182
Transport : & http.Transport {
149
183
TLSClientConfig : & tls.Config {InsecureSkipVerify : ! * sslVerify },
150
184
},
@@ -160,15 +194,15 @@ func main() {
160
194
if * nginxPlus {
161
195
plusClient , err := createClientWithRetries (func () (interface {}, error ) {
162
196
return plusclient .NewNginxClient (httpClient , * scrapeURI )
163
- }, * nginxRetries , * nginxRetryInterval )
197
+ }, * nginxRetries , nginxRetryInterval . Duration )
164
198
if err != nil {
165
199
log .Fatalf ("Could not create Nginx Plus Client: %v" , err )
166
200
}
167
201
registry .MustRegister (collector .NewNginxPlusCollector (plusClient .(* plusclient.NginxClient ), "nginxplus" ))
168
202
} else {
169
203
ossClient , err := createClientWithRetries (func () (interface {}, error ) {
170
204
return client .NewNginxClient (httpClient , * scrapeURI )
171
- }, * nginxRetries , * nginxRetryInterval )
205
+ }, * nginxRetries , nginxRetryInterval . Duration )
172
206
if err != nil {
173
207
log .Fatalf ("Could not create Nginx Client: %v" , err )
174
208
}
0 commit comments