Simplify Prometheus metrics gather (#15210)

This commit is contained in:
Harshavardhana 2022-07-01 13:18:39 -07:00 committed by GitHub
parent a01a39b153
commit 63ac260bd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 111 additions and 48 deletions

View File

@ -31,8 +31,8 @@ import (
"github.com/minio/minio/internal/bucket/lifecycle" "github.com/minio/minio/internal/bucket/lifecycle"
"github.com/minio/minio/internal/logger" "github.com/minio/minio/internal/logger"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
"github.com/prometheus/common/expfmt"
"github.com/prometheus/procfs" "github.com/prometheus/procfs"
) )
@ -2130,55 +2130,89 @@ func metricsServerHandler() http.Handler {
registry := prometheus.NewRegistry() registry := prometheus.NewRegistry()
// Report all other metrics // Report all other metrics
err := registry.Register(clusterCollector) logger.CriticalIf(GlobalContext, registry.Register(clusterCollector))
if err != nil {
logger.CriticalIf(GlobalContext, err)
}
// DefaultGatherers include golang metrics and process metrics. // DefaultGatherers include golang metrics and process metrics.
gatherers := prometheus.Gatherers{ gatherers := prometheus.Gatherers{
registry, registry,
} }
// Delegate http serving to Prometheus client library, which will call collector.Collect. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
return promhttp.InstrumentMetricHandler( tc, ok := r.Context().Value(contextTraceReqKey).(*traceCtxt)
registry, if ok {
promhttp.HandlerFor(gatherers, tc.funcName = "handler.MetricsCluster"
promhttp.HandlerOpts{ tc.responseRecorder.LogErrBody = true
ErrorHandling: promhttp.ContinueOnError, }
}),
) mfs, err := gatherers.Gather()
if err != nil {
if len(mfs) == 0 {
writeErrorResponseJSON(r.Context(), w, toAdminAPIErr(r.Context(), err), r.URL)
return
}
}
contentType := expfmt.Negotiate(r.Header)
w.Header().Set("Content-Type", string(contentType))
enc := expfmt.NewEncoder(w, contentType)
for _, mf := range mfs {
if err := enc.Encode(mf); err != nil {
logger.LogIf(r.Context(), err)
return
}
}
if closer, ok := enc.(expfmt.Closer); ok {
closer.Close()
}
})
} }
func metricsNodeHandler() http.Handler { func metricsNodeHandler() http.Handler {
registry := prometheus.NewRegistry() registry := prometheus.NewRegistry()
err := registry.Register(nodeCollector) logger.CriticalIf(GlobalContext, registry.Register(nodeCollector))
if err != nil { if err := registry.Register(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{
logger.CriticalIf(GlobalContext, err)
}
err = registry.Register(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{
Namespace: minioNamespace, Namespace: minioNamespace,
ReportErrors: true, ReportErrors: true,
})) })); err != nil {
if err != nil {
logger.CriticalIf(GlobalContext, err) logger.CriticalIf(GlobalContext, err)
} }
err = registry.Register(prometheus.NewGoCollector()) if err := registry.Register(prometheus.NewGoCollector()); err != nil {
if err != nil {
logger.CriticalIf(GlobalContext, err) logger.CriticalIf(GlobalContext, err)
} }
gatherers := prometheus.Gatherers{ gatherers := prometheus.Gatherers{
registry, registry,
} }
// Delegate http serving to Prometheus client library, which will call collector.Collect. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
return promhttp.InstrumentMetricHandler( tc, ok := r.Context().Value(contextTraceReqKey).(*traceCtxt)
registry, if ok {
promhttp.HandlerFor(gatherers, tc.funcName = "handler.MetricsNode"
promhttp.HandlerOpts{ tc.responseRecorder.LogErrBody = true
ErrorHandling: promhttp.ContinueOnError, }
}),
) mfs, err := gatherers.Gather()
if err != nil {
if len(mfs) == 0 {
writeErrorResponseJSON(r.Context(), w, toAdminAPIErr(r.Context(), err), r.URL)
return
}
}
contentType := expfmt.Negotiate(r.Header)
w.Header().Set("Content-Type", string(contentType))
enc := expfmt.NewEncoder(w, contentType)
for _, mf := range mfs {
if err := enc.Encode(mf); err != nil {
logger.LogIf(r.Context(), err)
return
}
}
if closer, ok := enc.(expfmt.Closer); ok {
closer.Close()
}
})
} }
func toSnake(camel string) (snake string) { func toSnake(camel string) (snake string) {

View File

@ -26,7 +26,7 @@ import (
"github.com/minio/minio/internal/logger" "github.com/minio/minio/internal/logger"
iampolicy "github.com/minio/pkg/iam/policy" iampolicy "github.com/minio/pkg/iam/policy"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/expfmt"
) )
var ( var (
@ -648,35 +648,59 @@ func storageMetricsPrometheus(ch chan<- prometheus.Metric) {
func metricsHandler() http.Handler { func metricsHandler() http.Handler {
registry := prometheus.NewRegistry() registry := prometheus.NewRegistry()
err := registry.Register(minioVersionInfo) logger.CriticalIf(GlobalContext, registry.Register(minioVersionInfo))
logger.LogIf(GlobalContext, err)
err = registry.Register(httpRequestsDuration) logger.CriticalIf(GlobalContext, registry.Register(newMinioCollector()))
logger.LogIf(GlobalContext, err)
err = registry.Register(newMinioCollector())
logger.LogIf(GlobalContext, err)
gatherers := prometheus.Gatherers{ gatherers := prometheus.Gatherers{
prometheus.DefaultGatherer, prometheus.DefaultGatherer,
registry, registry,
} }
// Delegate http serving to Prometheus client library, which will call collector.Collect.
return promhttp.InstrumentMetricHandler( return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
registry, tc, ok := r.Context().Value(contextTraceReqKey).(*traceCtxt)
promhttp.HandlerFor(gatherers, if ok {
promhttp.HandlerOpts{ tc.funcName = "handler.MetricsLegacy"
ErrorHandling: promhttp.ContinueOnError, tc.responseRecorder.LogErrBody = true
}), }
)
mfs, err := gatherers.Gather()
if err != nil {
if len(mfs) == 0 {
writeErrorResponseJSON(r.Context(), w, toAdminAPIErr(r.Context(), err), r.URL)
return
}
}
contentType := expfmt.Negotiate(r.Header)
w.Header().Set("Content-Type", string(contentType))
enc := expfmt.NewEncoder(w, contentType)
for _, mf := range mfs {
if err := enc.Encode(mf); err != nil {
logger.LogIf(r.Context(), err)
return
}
}
if closer, ok := enc.(expfmt.Closer); ok {
closer.Close()
}
})
} }
// AuthMiddleware checks if the bearer token is valid and authorized. // AuthMiddleware checks if the bearer token is valid and authorized.
func AuthMiddleware(h http.Handler) http.Handler { func AuthMiddleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tc, ok := r.Context().Value(contextTraceReqKey).(*traceCtxt)
claims, groups, owner, authErr := metricsRequestAuthenticate(r) claims, groups, owner, authErr := metricsRequestAuthenticate(r)
if authErr != nil || !claims.VerifyIssuer("prometheus", true) { if authErr != nil || !claims.VerifyIssuer("prometheus", true) {
w.WriteHeader(http.StatusForbidden) if ok {
tc.funcName = "handler.MetricsAuth"
tc.responseRecorder.LogErrBody = true
}
writeErrorResponseJSON(r.Context(), w, toAdminAPIErr(r.Context(), errAuthentication), r.URL)
return return
} }
// For authenticated users apply IAM policy. // For authenticated users apply IAM policy.
@ -688,7 +712,12 @@ func AuthMiddleware(h http.Handler) http.Handler {
IsOwner: owner, IsOwner: owner,
Claims: claims.Map(), Claims: claims.Map(),
}) { }) {
w.WriteHeader(http.StatusForbidden) if ok {
tc.funcName = "handler.MetricsAuth"
tc.responseRecorder.LogErrBody = true
}
writeErrorResponseJSON(r.Context(), w, toAdminAPIErr(r.Context(), errAuthentication), r.URL)
return return
} }
h.ServeHTTP(w, r) h.ServeHTTP(w, r)