diff --git a/cmd/s3-gw/app.go b/cmd/s3-gw/app.go index b94e342f..4484243d 100644 --- a/cmd/s3-gw/app.go +++ b/cmd/s3-gw/app.go @@ -35,6 +35,8 @@ type ( obj layer.Client api api.Handler + metrics GateMetricsCollector + maxClients api.MaxClients webDone chan struct{} @@ -45,6 +47,10 @@ type ( KeyFile string CertFile string } + + GateMetricsCollector interface { + SetHealth(int32) + } ) func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App { @@ -57,6 +63,8 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App { obj layer.Client nc *notifications.Controller + gateMetrics GateMetricsCollector + prmPool pool.InitParameters reBalance = defaultRebalanceInterval @@ -180,6 +188,10 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App { l.Fatal("could not initialize API handler", zap.Error(err)) } + if v.GetBool(cfgEnableMetrics) { + gateMetrics = newGateMetrics() + } + return &App{ ctr: ctr, log: l, @@ -188,6 +200,8 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App { tls: tls, api: caller, + metrics: gateMetrics, + webDone: make(chan struct{}, 1), wrkDone: make(chan struct{}, 1), @@ -215,6 +229,10 @@ func (a *App) Wait() { zap.String("version", version.Version), ) + if a.metrics != nil { + a.metrics.SetHealth(1) + } + <-a.webDone // wait for web-server to be stopped a.log.Info("application finished") @@ -238,7 +256,6 @@ func (a *App) Server(ctx context.Context) { router := newS3Router() // Attach app-specific routes: - // attachHealthy(router, a.cli) attachMetrics(router, a.cfg, a.log) attachProfiler(router, a.cfg, a.log) diff --git a/cmd/s3-gw/app_healthy.go b/cmd/s3-gw/app_healthy.go index 61294ed9..6321dc6d 100644 --- a/cmd/s3-gw/app_healthy.go +++ b/cmd/s3-gw/app_healthy.go @@ -1,46 +1,46 @@ package main import ( - "fmt" - "net/http" - - "github.com/gorilla/mux" + "github.com/prometheus/client_golang/prometheus" ) -// Healthy is a health check interface. -type Healthy interface { - Status() error -} - const ( - healthyState = "NeoFS S3 Gateway is " - hdrContentType = "Content-Type" - defaultContentType = "text/plain; charset=utf-8" + namespace = "neofs_s3_gw" + stateSubsystem = "state" ) -//nolint:deadcode,unused // TODO -func attachHealthy(r *mux.Router, h Healthy) { - healthy := r.PathPrefix(systemPath + "/-"). - Subrouter(). - StrictSlash(true) - - healthy.HandleFunc("/ready", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set(hdrContentType, defaultContentType) - w.WriteHeader(http.StatusOK) - _, _ = fmt.Fprintln(w, healthyState+"ready") - }) - - healthy.HandleFunc("/healthy", func(w http.ResponseWriter, r *http.Request) { - code := http.StatusOK - msg := "healthy" - - if err := h.Status(); err != nil { - msg = "unhealthy: " + err.Error() - code = http.StatusBadRequest - } - - w.Header().Set(hdrContentType, defaultContentType) - w.WriteHeader(code) - _, _ = fmt.Fprintln(w, healthyState+msg) - }) +type GateMetrics struct { + stateMetrics +} + +type stateMetrics struct { + healthCheck prometheus.Gauge +} + +func newGateMetrics() *GateMetrics { + stateMetric := newStateMetrics() + stateMetric.register() + + return &GateMetrics{ + stateMetrics: stateMetric, + } +} + +func newStateMetrics() stateMetrics { + return stateMetrics{ + healthCheck: prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: namespace, + Subsystem: stateSubsystem, + Name: "health", + Help: "Current S3 gateway state", + }), + } +} + +func (m stateMetrics) register() { + prometheus.MustRegister(m.healthCheck) +} + +func (m stateMetrics) SetHealth(s int32) { + m.healthCheck.Set(float64(s)) }