metrics: Add rule action metrics

This commit is contained in:
WeebDataHoarder
2025-04-25 11:39:59 +02:00
parent d6d69d0192
commit bc0eaeca21
6 changed files with 41 additions and 13 deletions

View File

@@ -43,7 +43,8 @@ func init() {
return nil, fmt.Errorf("no registered challenges found in rule %s", ruleName) return nil, fmt.Errorf("no registered challenges found in rule %s", ruleName)
} }
passHandler, ok := Register[policy.RuleAction(strings.ToUpper(params.PassAction))] passAction := policy.RuleAction(strings.ToUpper(params.PassAction))
passHandler, ok := Register[passAction]
if !ok { if !ok {
return nil, fmt.Errorf("unknown pass action %s", params.PassAction) return nil, fmt.Errorf("unknown pass action %s", params.PassAction)
} }
@@ -53,7 +54,8 @@ func init() {
return nil, err return nil, err
} }
failHandler, ok := Register[policy.RuleAction(strings.ToUpper(params.FailAction))] failAction := policy.RuleAction(strings.ToUpper(params.FailAction))
failHandler, ok := Register[failAction]
if !ok { if !ok {
return nil, fmt.Errorf("unknown pass action %s", params.FailAction) return nil, fmt.Errorf("unknown pass action %s", params.FailAction)
} }
@@ -69,8 +71,10 @@ func init() {
Continue: cont, Continue: cont,
Challenges: regs, Challenges: regs,
PassAction: passActionHandler, PassAction: passAction,
FailAction: failActionHandler, PassActionHandler: passActionHandler,
FailAction: failAction,
FailActionHandler: failActionHandler,
}, nil }, nil
} }
Register[policy.RuleActionCHALLENGE] = func(state challenge.StateInterface, ruleName, ruleHash string, settings ast.Node) (Handler, error) { Register[policy.RuleActionCHALLENGE] = func(state challenge.StateInterface, ruleName, ruleHash string, settings ast.Node) (Handler, error) {
@@ -104,8 +108,10 @@ type Challenge struct {
Continue bool Continue bool
Challenges []*challenge.Registration Challenges []*challenge.Registration
PassAction Handler PassAction policy.RuleAction
FailAction Handler PassActionHandler Handler
FailAction policy.RuleAction
FailActionHandler Handler
} }
func (a Challenge) Handle(logger *slog.Logger, w http.ResponseWriter, r *http.Request, done func() (backend http.Handler)) (next bool, err error) { func (a Challenge) Handle(logger *slog.Logger, w http.ResponseWriter, r *http.Request, done func() (backend http.Handler)) (next bool, err error) {
@@ -120,7 +126,8 @@ func (a Challenge) Handle(logger *slog.Logger, w http.ResponseWriter, r *http.Re
} }
// we passed! // we passed!
return a.PassAction.Handle(logger.With("challenge", reg.Name), w, r, done) data.State.ActionHit(r, a.PassAction, logger)
return a.PassActionHandler.Handle(logger.With("challenge", reg.Name), w, r, done)
} }
} }
// none matched, issue challenges in sequential priority // none matched, issue challenges in sequential priority
@@ -146,7 +153,8 @@ func (a Challenge) Handle(logger *slog.Logger, w http.ResponseWriter, r *http.Re
return true, nil return true, nil
} }
return a.PassAction.Handle(logger.With("challenge", reg.Name), w, r, done) data.State.ActionHit(r, a.PassAction, logger)
return a.PassActionHandler.Handle(logger.With("challenge", reg.Name), w, r, done)
case challenge.VerifyResultNotOK: case challenge.VerifyResultNotOK:
// we have had the challenge checked, but it's not ok! // we have had the challenge checked, but it's not ok!
// safe to continue // safe to continue
@@ -160,7 +168,8 @@ func (a Challenge) Handle(logger *slog.Logger, w http.ResponseWriter, r *http.Re
continue continue
} }
return a.FailAction.Handle(logger, w, r, done) data.State.ActionHit(r, a.FailAction, logger)
return a.FailActionHandler.Handle(logger, w, r, done)
case challenge.VerifyResultNone: case challenge.VerifyResultNone:
// challenge was issued // challenge was issued
if reg.Class == challenge.ClassTransparent { if reg.Class == challenge.ClassTransparent {
@@ -177,5 +186,6 @@ func (a Challenge) Handle(logger *slog.Logger, w http.ResponseWriter, r *http.Re
} }
// nothing matched, execute default action // nothing matched, execute default action
return a.FailAction.Handle(logger, w, r, done) data.State.ActionHit(r, a.FailAction, logger)
return a.FailActionHandler.Handle(logger, w, r, done)
} }

View File

@@ -101,6 +101,7 @@ type StateInterface interface {
RuleHit(r *http.Request, name string, logger *slog.Logger) RuleHit(r *http.Request, name string, logger *slog.Logger)
RuleMiss(r *http.Request, name string, logger *slog.Logger) RuleMiss(r *http.Request, name string, logger *slog.Logger)
ActionHit(r *http.Request, name policy.RuleAction, logger *slog.Logger)
Logger(r *http.Request) *slog.Logger Logger(r *http.Request) *slog.Logger

View File

@@ -6,6 +6,7 @@ import (
"git.gammaspectra.live/git/go-away/embed" "git.gammaspectra.live/git/go-away/embed"
"git.gammaspectra.live/git/go-away/lib/action" "git.gammaspectra.live/git/go-away/lib/action"
"git.gammaspectra.live/git/go-away/lib/challenge" "git.gammaspectra.live/git/go-away/lib/challenge"
"git.gammaspectra.live/git/go-away/lib/policy"
"git.gammaspectra.live/git/go-away/utils" "git.gammaspectra.live/git/go-away/utils"
"html/template" "html/template"
"log/slog" "log/slog"
@@ -130,6 +131,7 @@ func (state *State) handleRequest(w http.ResponseWriter, r *http.Request) {
} }
state.RuleHit(r, "DEFAULT", lg) state.RuleHit(r, "DEFAULT", lg)
data.State.ActionHit(r, policy.RuleActionPASS, lg)
// default pass // default pass
_, _ = action.Pass{}.Handle(lg, w, r, func() http.Handler { _, _ = action.Pass{}.Handle(lg, w, r, func() http.Handler {

View File

@@ -76,6 +76,10 @@ func (state *State) RuleMiss(r *http.Request, name string, logger *slog.Logger)
state.metrics.Rule(name, "miss") state.metrics.Rule(name, "miss")
} }
func (state *State) ActionHit(r *http.Request, name policy.RuleAction, logger *slog.Logger) {
state.metrics.Action(name)
}
func (state *State) Logger(r *http.Request) *slog.Logger { func (state *State) Logger(r *http.Request) *slog.Logger {
return GetLoggerForRequest(r) return GetLoggerForRequest(r)
} }

View File

@@ -1,12 +1,14 @@
package lib package lib
import ( import (
"git.gammaspectra.live/git/go-away/lib/policy"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
) )
type stateMetrics struct { type stateMetrics struct {
rules *prometheus.CounterVec rules *prometheus.CounterVec
actions *prometheus.CounterVec
challenges *prometheus.CounterVec challenges *prometheus.CounterVec
} }
@@ -16,8 +18,12 @@ func newMetrics() *stateMetrics {
Name: "go-away_rule_results", Name: "go-away_rule_results",
Help: "The number of rule hits or misses", Help: "The number of rule hits or misses",
}, []string{"rule", "result"}), }, []string{"rule", "result"}),
actions: promauto.NewCounterVec(prometheus.CounterOpts{
Name: "go-away_action_results",
Help: "The number of each action issued",
}, []string{"action"}),
challenges: promauto.NewCounterVec(prometheus.CounterOpts{ challenges: promauto.NewCounterVec(prometheus.CounterOpts{
Name: "go-away_challenge_actions", Name: "go-away_challenge_results",
Help: "The number of challenges issued, passed or explicitly failed", Help: "The number of challenges issued, passed or explicitly failed",
}, []string{"challenge", "action"}), }, []string{"challenge", "action"}),
} }
@@ -27,6 +33,10 @@ func (metrics *stateMetrics) Rule(name, result string) {
metrics.rules.With(prometheus.Labels{"rule": name, "result": result}).Inc() metrics.rules.With(prometheus.Labels{"rule": name, "result": result}).Inc()
} }
func (metrics *stateMetrics) Challenge(name, action string) { func (metrics *stateMetrics) Action(action policy.RuleAction) {
metrics.challenges.With(prometheus.Labels{"challenge": name, "action": action}).Inc() metrics.actions.With(prometheus.Labels{"action": string(action)}).Inc()
}
func (metrics *stateMetrics) Challenge(name, result string) {
metrics.challenges.With(prometheus.Labels{"challenge": name, "action": result}).Inc()
} }

View File

@@ -109,6 +109,7 @@ func (rule RuleState) Evaluate(logger *slog.Logger, w http.ResponseWriter, r *ht
if out.Equal(types.True) == types.True { if out.Equal(types.True) == types.True {
data.State.RuleHit(r, rule.Name, logger) data.State.RuleHit(r, rule.Name, logger)
data.State.ActionHit(r, rule.Action, logger)
next, err = rule.Handler.Handle(lg, w, r, func() http.Handler { next, err = rule.Handler.Handle(lg, w, r, func() http.Handler {
r.Header.Set("X-Away-Rule", rule.Name) r.Header.Set("X-Away-Rule", rule.Name)
r.Header.Set("X-Away-Hash", rule.Hash) r.Header.Set("X-Away-Hash", rule.Hash)