mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-02 11:56:02 +02:00
If a request is made to the Pomerium metrics endpoint with an Accept header requesting the Prometheus protobuf exposition format, some metrics will be missing from the response. These missing metrics are obtained by replaying the incoming request to an OpenCensus metrics exporter. This exporter honors the request for the protobuf format, however Pomerium expects this response to be in the text format. We can avoid this mismatch by explicitly requesting the text format from the OpenCensus exporter, regardless of the incoming request's Accept header. (Note: the Pomerium metrics endpoint always responds with text format metrics, even if the protobuf format is requested.)
88 lines
2.7 KiB
Go
88 lines
2.7 KiB
Go
package metrics
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func newEnvoyMetricsHandler() http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte(`
|
|
# TYPE envoy_server_initialization_time_ms histogram
|
|
envoy_server_initialization_time_ms_bucket{le="0.5"} 0
|
|
envoy_server_initialization_time_ms_bucket{le="1"} 0
|
|
envoy_server_initialization_time_ms_bucket{le="5"} 0
|
|
envoy_server_initialization_time_ms_bucket{le="10"} 0
|
|
envoy_server_initialization_time_ms_bucket{le="25"} 0
|
|
envoy_server_initialization_time_ms_bucket{le="50"} 0
|
|
envoy_server_initialization_time_ms_bucket{le="100"} 0
|
|
envoy_server_initialization_time_ms_bucket{le="250"} 0
|
|
envoy_server_initialization_time_ms_bucket{le="500"} 1
|
|
envoy_server_initialization_time_ms_bucket{le="1000"} 1
|
|
`))
|
|
}
|
|
}
|
|
|
|
func getMetrics(t *testing.T, envoyURL *url.URL, header http.Header) []byte {
|
|
h, err := PrometheusHandler([]ScrapeEndpoint{{Name: "envoy", URL: *envoyURL}}, "test_installation_id", time.Second*20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
req := httptest.NewRequest(http.MethodGet, "http://test.local/metrics", nil)
|
|
if header != nil {
|
|
req.Header = header
|
|
}
|
|
rec := httptest.NewRecorder()
|
|
h.ServeHTTP(rec, req)
|
|
|
|
resp := rec.Result()
|
|
b, _ := io.ReadAll(resp.Body)
|
|
|
|
if resp == nil || resp.StatusCode != 200 {
|
|
t.Errorf("Metrics endpoint failed to respond: %s", b)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func Test_PrometheusHandler(t *testing.T) {
|
|
t.Run("no envoy", func(t *testing.T) {
|
|
b := getMetrics(t, &url.URL{}, nil)
|
|
|
|
if m, _ := regexp.Match(`(?m)^# HELP .*`, b); !m {
|
|
t.Errorf("Metrics endpoint did not contain any help messages: %s", b)
|
|
}
|
|
})
|
|
|
|
t.Run("with envoy", func(t *testing.T) {
|
|
fakeEnvoyMetricsServer := httptest.NewServer(newEnvoyMetricsHandler())
|
|
envoyURL, _ := url.Parse(fakeEnvoyMetricsServer.URL)
|
|
b := getMetrics(t, envoyURL, nil)
|
|
|
|
if m, _ := regexp.Match(`(?m)^go_.*`, b); !m {
|
|
t.Errorf("Metrics endpoint did not contain internal metrics: %s", b)
|
|
}
|
|
if m, _ := regexp.Match(`(?m)^# TYPE envoy_.*`, b); !m {
|
|
t.Errorf("Metrics endpoint did not contain envoy metrics: %s", b)
|
|
}
|
|
})
|
|
|
|
t.Run("with envoy, request protobuf format", func(t *testing.T) {
|
|
fakeEnvoyMetricsServer := httptest.NewServer(newEnvoyMetricsHandler())
|
|
envoyURL, _ := url.Parse(fakeEnvoyMetricsServer.URL)
|
|
header := http.Header{}
|
|
header.Set("Accept", "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited")
|
|
b := getMetrics(t, envoyURL, header)
|
|
|
|
if m, _ := regexp.Match(`(?m)^go_.*`, b); !m {
|
|
t.Errorf("Metrics endpoint did not contain internal metrics: %s", b)
|
|
}
|
|
if m, _ := regexp.Match(`(?m)^# TYPE envoy_.*`, b); !m {
|
|
t.Errorf("Metrics endpoint did not contain envoy metrics: %s", b)
|
|
}
|
|
})
|
|
}
|