Expose HTTP version of probe (#189)
authorConor Broderick <conor.broderick@robustperception.io>
Tue, 11 Jul 2017 16:14:07 +0000 (17:14 +0100)
committerBrian Brazil <brian.brazil@robustperception.io>
Tue, 11 Jul 2017 16:14:07 +0000 (17:14 +0100)
CONFIGURATION.md
config.go
example.yml
http.go
http_test.go

index 20c665a94814478d93bdfeec02f21b8e926c52cc..c036cdbf1cd73fed0f5e29183c4f81244007c021 100644 (file)
@@ -38,6 +38,9 @@ The other placeholders are specified separately.
   # Accepted status codes for this probe. Defaults to 2xx.
   [ valid_status_codes: <string>, ... | default = "2xx" ]
 
+  # Accepted HTTP versions for this probe.
+  [ valid_http_versions: <string>, ... ]
+
   # The HTTP method the probe will use.
   [ method: <string> | default = "GET" ]
 
index 5e2978880ea29c04ffe9c82b0d722fb6f23dc04f..91880daf1c7a8ad491c87b05ca6720d65bd2d335 100644 (file)
--- a/config.go
+++ b/config.go
@@ -36,6 +36,7 @@ type Module struct {
 type HTTPProbe struct {
        // Defaults to 2xx.
        ValidStatusCodes       []int                   `yaml:"valid_status_codes,omitempty"`
+       ValidHTTPVersions      []string                `yaml:"valid_http_versions,omitempty"`
        PreferredIPProtocol    string                  `yaml:"preferred_ip_protocol,omitempty"`
        NoFollowRedirects      bool                    `yaml:"no_follow_redirects,omitempty"`
        FailIfSSL              bool                    `yaml:"fail_if_ssl,omitempty"`
index b2bcc460a1a8fc40c70c3a183a3810d698b14643..891b59d07f912faa4fbc27feb7136fed2d4596f3 100644 (file)
@@ -3,6 +3,7 @@ modules:
     prober: http
     timeout: 5s
     http:
+      valid_http_versions: ["HTTP/1.1", "HTTP/2"]
       valid_status_codes: []  # Defaults to 2xx
       method: GET
       headers:
diff --git a/http.go b/http.go
index cb9128877c9939463b1c42b8e61d5c4d47bf4a9e..217a2f6a2f1b9c8907515d03ecc7cf646527a18c 100644 (file)
--- a/http.go
+++ b/http.go
@@ -21,6 +21,7 @@ import (
        "net/http"
        "net/url"
        "regexp"
+       "strconv"
        "strings"
 
        "github.com/prometheus/client_golang/prometheus"
@@ -85,12 +86,18 @@ func probeHTTP(target string, module Module, registry *prometheus.Registry) (suc
                        Name: "probe_ssl_earliest_cert_expiry",
                        Help: "Returns earliest SSL cert expiry in unixtime",
                })
+
+               probeHTTPVersionGauge = prometheus.NewGauge(prometheus.GaugeOpts{
+                       Name: "probe_http_version",
+                       Help: "Returns the version of HTTP of the probe response",
+               })
        )
 
        registry.MustRegister(contentLengthGauge)
        registry.MustRegister(redirectsGauge)
        registry.MustRegister(isSSLGauge)
        registry.MustRegister(statusCodeGauge)
+       registry.MustRegister(probeHTTPVersionGauge)
 
        httpConfig := module.HTTP
 
@@ -160,7 +167,6 @@ func probeHTTP(target string, module Module, registry *prometheus.Registry) (suc
                request.Body = ioutil.NopCloser(strings.NewReader(httpConfig.Body))
        }
        resp, err := client.Do(request)
-
        // Err won't be nil if redirects were turned off. See https://github.com/golang/go/issues/3795
        if err != nil && resp == nil {
                log.Warnf("Error for HTTP request to %s: %s", target, err)
@@ -180,6 +186,27 @@ func probeHTTP(target string, module Module, registry *prometheus.Registry) (suc
                if success && (len(httpConfig.FailIfMatchesRegexp) > 0 || len(httpConfig.FailIfNotMatchesRegexp) > 0) {
                        success = matchRegularExpressions(resp.Body, httpConfig)
                }
+
+               var httpVersionNumber float64
+               httpVersionNumber, err = strconv.ParseFloat(strings.TrimPrefix(resp.Proto, "HTTP/"), 64)
+               if err != nil {
+                       log.Errorf("Error parsing version number from HTTP version: %v", err)
+               }
+               probeHTTPVersionGauge.Set(httpVersionNumber)
+
+               if len(httpConfig.ValidHTTPVersions) != 0 {
+                       found := false
+                       for _, version := range httpConfig.ValidHTTPVersions {
+                               if version == resp.Proto {
+                                       found = true
+                                       break
+                               }
+                       }
+                       if !found {
+                               success = false
+                       }
+               }
+
        }
 
        if resp == nil {
index 976a30077cf76d30973d8832f561639fd5dee598..443d6890b2aeefa1d6f957e48ae2cc0de9b5fa56 100644 (file)
@@ -58,6 +58,33 @@ func TestHTTPStatusCodes(t *testing.T) {
        }
 }
 
+func TestValidHTTPVersion(t *testing.T) {
+       tests := []struct {
+               ValidHTTPVersions []string
+               ShouldSucceed     bool
+       }{
+               {[]string{}, true},
+               {[]string{"HTTP/1.1"}, true},
+               {[]string{"HTTP/1.1", "HTTP/2"}, true},
+               {[]string{"HTTP/2"}, false},
+       }
+       for i, test := range tests {
+               ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               }))
+               defer ts.Close()
+               recorder := httptest.NewRecorder()
+               registry := prometheus.NewRegistry()
+               result := probeHTTP(ts.URL,
+                       Module{Timeout: time.Second, HTTP: HTTPProbe{
+                               ValidHTTPVersions: test.ValidHTTPVersions,
+                       }}, registry)
+               body := recorder.Body.String()
+               if result != test.ShouldSucceed {
+                       t.Fatalf("Test %v had unexpected result: %s", i, body)
+               }
+       }
+}
+
 func TestRedirectFollowed(t *testing.T) {
        ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                if r.URL.Path == "/" {