Skip to content

Commit d1807d5

Browse files
author
Romain Dartigues
committed
change the Accept header sent to the exporters
Création d'une nouvelle version de l'API (`/v2`) qui change l'entête HTTP `Accept` envoyée aux exporters des clients car la bibliothèque Go que nous utilisons afin de parser et enrichir les exporters de nos clients ne sait pas gérer le format OpenMetrics [1] qui peut être retournée par des exporters suivant la spécification. Les requêtes envoyées à nos clients contiennent désormais une entête HTTP leur indiquant la version de l'API interrogée. [1]: prometheus/client_golang#829 (comment) [2]: prometheus/common#214 JIRA: PAASCFY-2126
1 parent de8eb40 commit d1807d5

File tree

4 files changed

+48
-8
lines changed

4 files changed

+48
-8
lines changed

Diff for: api/init.go

+22-5
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,37 @@ func Register(rtr *mux.Router, metFetcher *fetchers.MetricsFetcher, broker *Brok
2222
}
2323

2424
handlerMetrics := handlers.CompressHandler(http.HandlerFunc(api.metrics))
25-
rtr.Handle("/v1/apps/{appIdOrPathOrName:.*}/metrics", handlerMetrics).
25+
handlerOnlyAppMetrics := handlers.CompressHandler(forceOnlyForApp(http.HandlerFunc(api.metrics)))
26+
27+
// API v1: deprecated
28+
routerApiV1 := rtr.PathPrefix("/v1").Subrouter()
29+
routerApiV1.Handle("/apps/{appIdOrPathOrName:.*}/metrics", handlerMetrics).
2630
Methods(http.MethodGet)
2731

28-
rtr.Handle("/v1/apps/metrics", handlerMetrics).
32+
routerApiV1.Handle("/apps/metrics", handlerMetrics).
2933
Methods(http.MethodGet)
3034

31-
handlerOnlyAppMetrics := handlers.CompressHandler(forceOnlyForApp(http.HandlerFunc(api.metrics)))
35+
routerApiV1.Handle("/apps/{appIdOrPathOrName:.*}/only-app-metrics", handlerOnlyAppMetrics).
36+
Methods(http.MethodGet)
37+
38+
routerApiV1.Handle("/apps/only-app-metrics", handlerOnlyAppMetrics).
39+
Methods(http.MethodGet)
40+
41+
// API v2
42+
routerApiV2 := rtr.PathPrefix("/v2").Subrouter()
43+
routerApiV2.Handle("/apps/{appIdOrPathOrName:.*}/metrics", handlerMetrics).
44+
Methods(http.MethodGet)
45+
46+
routerApiV2.Handle("/apps/metrics", handlerMetrics).
47+
Methods(http.MethodGet)
3248

33-
rtr.Handle("/v1/apps/{appIdOrPathOrName:.*}/only-app-metrics", handlerOnlyAppMetrics).
49+
routerApiV2.Handle("/apps/{appIdOrPathOrName:.*}/only-app-metrics", handlerOnlyAppMetrics).
3450
Methods(http.MethodGet)
3551

36-
rtr.Handle("/v1/apps/only-app-metrics", handlerOnlyAppMetrics).
52+
routerApiV2.Handle("/apps/only-app-metrics", handlerOnlyAppMetrics).
3753
Methods(http.MethodGet)
3854

55+
// non-API routes
3956
rtr.NewRoute().MatcherFunc(func(req *http.Request, m *mux.RouteMatch) bool {
4057
return strings.HasPrefix(req.URL.Path, "/broker/v2")
4158
}).Handler(http.StripPrefix("/broker", broker.Handler()))

Diff for: api/metrics.go

+12
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,27 @@ package api
33
import (
44
"fmt"
55
"net/http"
6+
"regexp"
67
"strings"
78

89
"github.com/gorilla/mux"
10+
"github.com/orange-cloudfoundry/promfetcher/models"
911
"github.com/prometheus/common/expfmt"
1012

1113
"github.com/orange-cloudfoundry/promfetcher/errors"
1214
)
1315

1416
func (a Api) metrics(w http.ResponseWriter, req *http.Request) {
17+
// extract the API version from the requested path (ie: /v2)
18+
// and set it to an HTTP header
19+
apiVersion := regexp.MustCompile("/v([0-9]+)(?:/|$)").FindStringSubmatch(req.URL.Path)
20+
if len(apiVersion) == 2 {
21+
req.Header.Set(models.XPromfetcherApiVersion, apiVersion[1])
22+
} else {
23+
// default to v1
24+
req.Header.Set(models.XPromfetcherApiVersion, "1")
25+
}
26+
1527
appIdOrPathOrName, ok := mux.Vars(req)["appIdOrPathOrName"]
1628
if !ok {
1729
appIdOrPathOrName = req.URL.Query().Get("app")

Diff for: models/api.go

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package models
2+
3+
//XPromfetcherApiVersion name of the HTTP header corresponding to the Promfetcher API version
4+
const XPromfetcherApiVersion = `X-Promfetcher-API-version`

Diff for: scrapers/scrape.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ import (
1212
"github.com/orange-cloudfoundry/promfetcher/clients"
1313
"github.com/orange-cloudfoundry/promfetcher/errors"
1414
"github.com/orange-cloudfoundry/promfetcher/models"
15+
"github.com/prometheus/common/expfmt"
1516
)
1617

17-
const acceptHeader = `application/openmetrics-text; version=0.0.1,text/plain;version=0.0.4;q=0.5,*/*;q=0.1`
18-
1918
type Scraper struct {
2019
backendFactory *clients.BackendFactory
2120
db *gorm.DB
@@ -69,7 +68,15 @@ func (s Scraper) Scrape(route *models.Route, metricPathDefault string, headers h
6968
req.Header[k] = v
7069
}
7170
}
72-
req.Header.Add("Accept", acceptHeader)
71+
// Prometheus parser is not OpenMetrics compliant
72+
// See: prometheus/common issues: 214, 829
73+
req.Header.Set("Accept", string(expfmt.FmtText))
74+
// keep the OpenMetrics accept HTTP header for the /v1 endpoint
75+
// See: PAASCFY-2105 and PAASCFY-2126
76+
if req.Header.Get(models.XPromfetcherApiVersion) == "1" {
77+
req.Header.Set(models.XPromfetcherApiVersion, "1")
78+
req.Header.Set("Accept", `application/openmetrics-text; version=0.0.1,text/plain;version=0.0.4;q=0.5,*/*;q=0.1`)
79+
}
7380
req.Header.Add("Accept-Encoding", "gzip")
7481
req.Header.Set("X-Prometheus-Scrape-Timeout-Seconds", fmt.Sprintf("%f", (30*time.Second).Seconds()))
7582
req.Header.Set("X-Forwarded-Proto", scheme)

0 commit comments

Comments
 (0)