pomerium/internal/telemetry/metrics/providers.go
Travis Groth d514ec2ecf Proxy envoy metrics through control plane prometheus endpoint (#709)
* Proxy metrics requests to envoy control plane
2020-05-18 17:10:10 -04:00

83 lines
2.3 KiB
Go

package metrics
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
ocprom "contrib.go.opencensus.io/exporter/prometheus"
prom "github.com/prometheus/client_golang/prometheus"
"go.opencensus.io/stats/view"
"github.com/pomerium/pomerium/internal/envoy"
log "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/urlutil"
)
var envoyURL = envoy.EnvoyAdminURL
// PrometheusHandler creates an exporter that exports stats to Prometheus
// and returns a handler suitable for exporting metrics.
func PrometheusHandler() (http.Handler, error) {
if err := registerDefaultViews(); err != nil {
return nil, fmt.Errorf("telemetry/metrics: failed registering views")
}
reg := prom.DefaultRegisterer.(*prom.Registry)
exporter, err := ocprom.NewExporter(
ocprom.Options{
Namespace: "pomerium",
Registry: reg,
})
if err != nil {
return nil, fmt.Errorf("telemetry/metrics: prometheus exporter: %w", err)
}
view.RegisterExporter(exporter)
mux := http.NewServeMux()
envoyMetricsURL, err := urlutil.ParseAndValidateURL(fmt.Sprintf("%s/stats/prometheus", envoyURL))
if err != nil {
return nil, fmt.Errorf("telemetry/metrics: invalid proxy URL: %w", err)
}
mux.Handle("/metrics", newProxyMetricsHandler(exporter, *envoyMetricsURL))
return mux, nil
}
func registerDefaultViews() error {
var views []*view.View
for _, v := range DefaultViews {
views = append(views, v...)
}
return view.Register(views...)
}
// newProxyMetricsHandler creates a subrequest to the envoy control plane for metrics and
// combines them with our own
func newProxyMetricsHandler(promHandler http.Handler, envoyURL url.URL) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
defer promHandler.ServeHTTP(w, r)
r, err := http.NewRequestWithContext(r.Context(), "GET", envoyURL.String(), nil)
if err != nil {
log.Error().Err(err).Msg("telemetry/metrics: failed to create request for envoy")
return
}
resp, err := http.DefaultClient.Do(r)
if err != nil {
log.Error().Err(err).Msg("telemetry/metrics: fail to fetch proxy metrics")
return
}
defer resp.Body.Close()
envoyBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error().Err(err).Msg("telemetry/metric: failed to read proxy metrics")
return
}
w.Write(envoyBody)
}
}