feat(metrics): add metrics for successful logins and logouts

This commit is contained in:
Trong Huu Nguyen
2022-07-19 09:25:43 +02:00
parent 0d0f75d21e
commit cbb6be135a
5 changed files with 93 additions and 6 deletions

View File

@@ -10,6 +10,7 @@ import (
log "github.com/sirupsen/logrus"
"github.com/nais/wonderwall/pkg/loginstatus"
"github.com/nais/wonderwall/pkg/metrics"
logentry "github.com/nais/wonderwall/pkg/middleware"
"github.com/nais/wonderwall/pkg/openid"
"github.com/nais/wonderwall/pkg/openid/client"
@@ -120,4 +121,5 @@ func logSuccessfulLogin(r *http.Request, tokens *openid.Tokens, referer string)
}
logentry.LogEntry(r).WithFields(fields).Info("callback: successful login")
metrics.ObserveLogin()
}

View File

@@ -4,6 +4,7 @@ import (
"net/http"
"github.com/nais/wonderwall/pkg/cookie"
"github.com/nais/wonderwall/pkg/metrics"
logentry "github.com/nais/wonderwall/pkg/middleware"
)
@@ -31,14 +32,19 @@ func (h *Handler) FrontChannelLogout(w http.ResponseWriter, r *http.Request) {
sessionData, err := h.getSession(r, sessionID)
if err != nil {
logger.Infof("front-channel logout: getting session (user might already be logged out): %+v", err)
w.WriteHeader(http.StatusAccepted)
return
}
err = h.destroySession(w, r, sessionID)
if err != nil {
logger.Warnf("front-channel logout: destroying session: %+v", err)
w.WriteHeader(http.StatusAccepted)
return
} else if sessionData != nil {
logger.WithField("jti", sessionData.IDTokenJwtID).Infof("front-channel logout: successful logout")
}
metrics.ObserveLogout(metrics.LogoutOperationFrontChannel)
w.WriteHeader(http.StatusOK)
}

View File

@@ -8,6 +8,7 @@ import (
log "github.com/sirupsen/logrus"
"github.com/nais/wonderwall/pkg/cookie"
"github.com/nais/wonderwall/pkg/metrics"
logentry "github.com/nais/wonderwall/pkg/middleware"
"github.com/nais/wonderwall/pkg/session"
)
@@ -46,5 +47,6 @@ func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) {
}
logger.Info("logout: redirecting to identity provider")
metrics.ObserveLogout(metrics.LogoutOperationSelfInitiated)
http.Redirect(w, r, logout.SingleLogoutURL(idToken), http.StatusTemporaryRedirect)
}

View File

@@ -11,7 +11,29 @@ import (
const (
Namespace = "wonderwall"
RedisOperationLabel = "operation"
LabelOperation = "operation"
LabelHpa = "hpa"
)
type Hpa = string
const (
HpaRate = "rate"
)
type LogoutOperation = string
const (
LogoutOperationSelfInitiated = "self_initiated"
LogoutOperationFrontChannel = "front_channel"
)
type RedisOperation = string
const (
RedisOperationRead = "Read"
RedisOperationWrite = "Write"
RedisOperationDelete = "Delete"
)
var (
@@ -20,11 +42,51 @@ var (
Namespace: Namespace,
Help: "latency in redis operations",
Buckets: prometheus.ExponentialBuckets(0.02, 2, 14),
}, []string{RedisOperationLabel})
}, []string{LabelOperation})
Logins = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "logins",
Namespace: Namespace,
Help: "cumulative number of successful logins",
},
[]string{
LabelHpa,
},
)
Logouts = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "logouts",
Namespace: Namespace,
Help: "cumulative number of successful logouts",
},
[]string{
LabelOperation,
LabelHpa,
},
)
)
// InitLabels zeroes out all possible label combinations
func InitLabels() {
logoutOperations := []LogoutOperation{LogoutOperationSelfInitiated, LogoutOperationFrontChannel}
for _, operation := range logoutOperations {
Logouts.With(prometheus.Labels{
LabelOperation: operation,
LabelHpa: HpaRate,
})
}
Logins.With(prometheus.Labels{
LabelHpa: HpaRate,
})
}
func Handle(address string) error {
Register(prometheus.DefaultRegisterer)
InitLabels()
handler := promhttp.Handler()
return http.ListenAndServe(address, handler)
}
@@ -32,6 +94,8 @@ func Handle(address string) error {
func Register(registry prometheus.Registerer) {
registry.MustRegister(
RedisLatency,
Logins,
Logouts,
)
}
@@ -40,7 +104,20 @@ func ObserveRedisLatency(operation string, fun func() error) error {
err := fun()
used := time.Now().Sub(timer)
RedisLatency.With(prometheus.Labels{
RedisOperationLabel: operation,
LabelOperation: operation,
}).Observe(used.Seconds())
return err
}
func ObserveLogin() {
Logins.With(prometheus.Labels{
LabelHpa: HpaRate,
}).Inc()
}
func ObserveLogout(operation LogoutOperation) {
Logouts.With(prometheus.Labels{
LabelOperation: operation,
LabelHpa: HpaRate,
}).Inc()
}

View File

@@ -25,7 +25,7 @@ func NewRedis(client redis.Cmdable) Store {
func (s *redisSessionStore) Read(ctx context.Context, key string) (*EncryptedData, error) {
encryptedData := &EncryptedData{}
err := metrics.ObserveRedisLatency("Read", func() error {
err := metrics.ObserveRedisLatency(metrics.RedisOperationRead, func() error {
return s.client.Get(ctx, key).Scan(encryptedData)
})
if err == nil {
@@ -40,13 +40,13 @@ func (s *redisSessionStore) Read(ctx context.Context, key string) (*EncryptedDat
}
func (s *redisSessionStore) Write(ctx context.Context, key string, value *EncryptedData, expiration time.Duration) error {
return metrics.ObserveRedisLatency("Write", func() error {
return metrics.ObserveRedisLatency(metrics.RedisOperationWrite, func() error {
return s.client.Set(ctx, key, value, expiration).Err()
})
}
func (s *redisSessionStore) Delete(ctx context.Context, keys ...string) error {
err := metrics.ObserveRedisLatency("Delete", func() error {
err := metrics.ObserveRedisLatency(metrics.RedisOperationDelete, func() error {
return s.client.Del(ctx, keys...).Err()
})
if err == nil {