forked from TrueCloudLab/frostfs-s3-gw
[#600] Add health metric
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
757600608c
commit
89d240d831
2 changed files with 55 additions and 38 deletions
|
@ -35,6 +35,8 @@ type (
|
||||||
obj layer.Client
|
obj layer.Client
|
||||||
api api.Handler
|
api api.Handler
|
||||||
|
|
||||||
|
metrics GateMetricsCollector
|
||||||
|
|
||||||
maxClients api.MaxClients
|
maxClients api.MaxClients
|
||||||
|
|
||||||
webDone chan struct{}
|
webDone chan struct{}
|
||||||
|
@ -45,6 +47,10 @@ type (
|
||||||
KeyFile string
|
KeyFile string
|
||||||
CertFile string
|
CertFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GateMetricsCollector interface {
|
||||||
|
SetHealth(int32)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
|
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
|
obj layer.Client
|
||||||
nc *notifications.Controller
|
nc *notifications.Controller
|
||||||
|
|
||||||
|
gateMetrics GateMetricsCollector
|
||||||
|
|
||||||
prmPool pool.InitParameters
|
prmPool pool.InitParameters
|
||||||
|
|
||||||
reBalance = defaultRebalanceInterval
|
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))
|
l.Fatal("could not initialize API handler", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v.GetBool(cfgEnableMetrics) {
|
||||||
|
gateMetrics = newGateMetrics()
|
||||||
|
}
|
||||||
|
|
||||||
return &App{
|
return &App{
|
||||||
ctr: ctr,
|
ctr: ctr,
|
||||||
log: l,
|
log: l,
|
||||||
|
@ -188,6 +200,8 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
|
||||||
tls: tls,
|
tls: tls,
|
||||||
api: caller,
|
api: caller,
|
||||||
|
|
||||||
|
metrics: gateMetrics,
|
||||||
|
|
||||||
webDone: make(chan struct{}, 1),
|
webDone: make(chan struct{}, 1),
|
||||||
wrkDone: make(chan struct{}, 1),
|
wrkDone: make(chan struct{}, 1),
|
||||||
|
|
||||||
|
@ -215,6 +229,10 @@ func (a *App) Wait() {
|
||||||
zap.String("version", version.Version),
|
zap.String("version", version.Version),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if a.metrics != nil {
|
||||||
|
a.metrics.SetHealth(1)
|
||||||
|
}
|
||||||
|
|
||||||
<-a.webDone // wait for web-server to be stopped
|
<-a.webDone // wait for web-server to be stopped
|
||||||
|
|
||||||
a.log.Info("application finished")
|
a.log.Info("application finished")
|
||||||
|
@ -238,7 +256,6 @@ func (a *App) Server(ctx context.Context) {
|
||||||
router := newS3Router()
|
router := newS3Router()
|
||||||
|
|
||||||
// Attach app-specific routes:
|
// Attach app-specific routes:
|
||||||
// attachHealthy(router, a.cli)
|
|
||||||
attachMetrics(router, a.cfg, a.log)
|
attachMetrics(router, a.cfg, a.log)
|
||||||
attachProfiler(router, a.cfg, a.log)
|
attachProfiler(router, a.cfg, a.log)
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Healthy is a health check interface.
|
|
||||||
type Healthy interface {
|
|
||||||
Status() error
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
healthyState = "NeoFS S3 Gateway is "
|
namespace = "neofs_s3_gw"
|
||||||
hdrContentType = "Content-Type"
|
stateSubsystem = "state"
|
||||||
defaultContentType = "text/plain; charset=utf-8"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:deadcode,unused // TODO
|
type GateMetrics struct {
|
||||||
func attachHealthy(r *mux.Router, h Healthy) {
|
stateMetrics
|
||||||
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)
|
type stateMetrics struct {
|
||||||
w.WriteHeader(code)
|
healthCheck prometheus.Gauge
|
||||||
_, _ = fmt.Fprintln(w, healthyState+msg)
|
}
|
||||||
})
|
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue