metrics: Added prometheus metrics for rules and challenges
This commit is contained in:
@@ -112,6 +112,9 @@ func (a Challenge) Handle(logger *slog.Logger, w http.ResponseWriter, r *http.Re
|
||||
data := challenge.RequestDataFromContext(r.Context())
|
||||
for _, reg := range a.Challenges {
|
||||
if data.HasValidChallenge(reg.Id()) {
|
||||
|
||||
data.State.ChallengeChecked(r, reg, r.URL.String(), logger)
|
||||
|
||||
if a.Continue {
|
||||
return true, nil
|
||||
}
|
||||
|
@@ -97,6 +97,10 @@ type StateInterface interface {
|
||||
ChallengeFailed(r *http.Request, reg *Registration, err error, redirect string, logger *slog.Logger)
|
||||
ChallengePassed(r *http.Request, reg *Registration, redirect string, logger *slog.Logger)
|
||||
ChallengeIssued(r *http.Request, reg *Registration, redirect string, logger *slog.Logger)
|
||||
ChallengeChecked(r *http.Request, reg *Registration, redirect string, logger *slog.Logger)
|
||||
|
||||
RuleHit(r *http.Request, name string, logger *slog.Logger)
|
||||
RuleMiss(r *http.Request, name string, logger *slog.Logger)
|
||||
|
||||
Logger(r *http.Request) *slog.Logger
|
||||
|
||||
|
@@ -43,7 +43,7 @@ func (state *State) ChallengeFailed(r *http.Request, reg *challenge.Registration
|
||||
}
|
||||
logger.Warn("challenge failed", "challenge", reg.Name, "err", err, "redirect", redirect)
|
||||
|
||||
//TODO: metrics
|
||||
state.metrics.Challenge(reg.Name, "fail")
|
||||
}
|
||||
|
||||
func (state *State) ChallengePassed(r *http.Request, reg *challenge.Registration, redirect string, logger *slog.Logger) {
|
||||
@@ -52,7 +52,7 @@ func (state *State) ChallengePassed(r *http.Request, reg *challenge.Registration
|
||||
}
|
||||
logger.Warn("challenge passed", "challenge", reg.Name, "redirect", redirect)
|
||||
|
||||
//TODO: metrics
|
||||
state.metrics.Challenge(reg.Name, "pass")
|
||||
}
|
||||
|
||||
func (state *State) ChallengeIssued(r *http.Request, reg *challenge.Registration, redirect string, logger *slog.Logger) {
|
||||
@@ -61,7 +61,19 @@ func (state *State) ChallengeIssued(r *http.Request, reg *challenge.Registration
|
||||
}
|
||||
logger.Info("challenge issued", "challenge", reg.Name, "redirect", redirect)
|
||||
|
||||
//TODO: metrics
|
||||
state.metrics.Challenge(reg.Name, "issue")
|
||||
}
|
||||
|
||||
func (state *State) ChallengeChecked(r *http.Request, reg *challenge.Registration, redirect string, logger *slog.Logger) {
|
||||
state.metrics.Challenge(reg.Name, "check")
|
||||
}
|
||||
|
||||
func (state *State) RuleHit(r *http.Request, name string, logger *slog.Logger) {
|
||||
state.metrics.Rule(name, "hit")
|
||||
}
|
||||
|
||||
func (state *State) RuleMiss(r *http.Request, name string, logger *slog.Logger) {
|
||||
state.metrics.Rule(name, "miss")
|
||||
}
|
||||
|
||||
func (state *State) Logger(r *http.Request) *slog.Logger {
|
||||
|
32
lib/metrics.go
Normal file
32
lib/metrics.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
type stateMetrics struct {
|
||||
rules *prometheus.CounterVec
|
||||
challenges *prometheus.CounterVec
|
||||
}
|
||||
|
||||
func newMetrics() *stateMetrics {
|
||||
return &stateMetrics{
|
||||
rules: promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "go-away_rule_results",
|
||||
Help: "The number of rule hits or misses",
|
||||
}, []string{"rule", "result"}),
|
||||
challenges: promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "go-away_challenge_actions",
|
||||
Help: "The number of challenges issued, passed or explicitly failed",
|
||||
}, []string{"challenge", "action"}),
|
||||
}
|
||||
}
|
||||
|
||||
func (metrics *stateMetrics) Rule(name, result string) {
|
||||
metrics.rules.With(prometheus.Labels{"rule": name, "result": result}).Inc()
|
||||
}
|
||||
|
||||
func (metrics *stateMetrics) Challenge(name, action string) {
|
||||
metrics.challenges.With(prometheus.Labels{"challenge": name, "action": action}).Inc()
|
||||
}
|
@@ -107,6 +107,8 @@ func (rule RuleState) Evaluate(logger *slog.Logger, w http.ResponseWriter, r *ht
|
||||
return false, fmt.Errorf("error: evaluating administrative rule %s/%s: %w", data.Id.String(), rule.Hash, err)
|
||||
} else if out != nil && out.Type() == types.BoolType {
|
||||
if out.Equal(types.True) == types.True {
|
||||
data.State.RuleHit(r, rule.Name, logger)
|
||||
|
||||
next, err = rule.Handler.Handle(lg, w, r, func() http.Handler {
|
||||
r.Header.Set("X-Away-Rule", rule.Name)
|
||||
r.Header.Set("X-Away-Hash", rule.Hash)
|
||||
@@ -134,7 +136,13 @@ func (rule RuleState) Evaluate(logger *slog.Logger, w http.ResponseWriter, r *ht
|
||||
return next, nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data.State.RuleMiss(r, rule.Name, logger)
|
||||
}
|
||||
} else if out != nil {
|
||||
err := fmt.Errorf("return type not Bool, got %s", out.Type().TypeName())
|
||||
lg.Error(err.Error())
|
||||
return false, fmt.Errorf("error: evaluating administrative rule %s/%s: %w", data.Id.String(), rule.Hash, err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
|
@@ -20,9 +20,16 @@ type Backend struct {
|
||||
|
||||
// TLSSkipVerify Disable TLS certificate verification, if any
|
||||
TLSSkipVerify bool `yaml:"tls-skip-verify"`
|
||||
|
||||
// IpHeader HTTP header to set containing the IP header. Set - to forcefully ignore global defaults.
|
||||
IpHeader string `yaml:"ip-header"`
|
||||
}
|
||||
|
||||
func (b Backend) Create() (*httputil.ReverseProxy, error) {
|
||||
if b.IpHeader == "-" {
|
||||
b.IpHeader = ""
|
||||
}
|
||||
|
||||
proxy, err := utils.MakeReverseProxy(b.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -40,9 +47,19 @@ func (b Backend) Create() (*httputil.ReverseProxy, error) {
|
||||
|
||||
if b.Host != "" {
|
||||
transport.TLSClientConfig.ServerName = b.Host
|
||||
}
|
||||
|
||||
if b.IpHeader != "" || b.Host != "" {
|
||||
director := proxy.Director
|
||||
proxy.Director = func(req *http.Request) {
|
||||
req.Host = b.Host
|
||||
if b.IpHeader != "" {
|
||||
if ip := utils.GetRemoteAddress(req.Context()); ip != nil {
|
||||
req.Header.Set(b.IpHeader, ip.Addr().Unmap().String())
|
||||
}
|
||||
}
|
||||
if b.Host != "" {
|
||||
req.Host = b.Host
|
||||
}
|
||||
director(req)
|
||||
}
|
||||
}
|
||||
|
@@ -44,6 +44,8 @@ type State struct {
|
||||
close chan struct{}
|
||||
|
||||
Mux *http.ServeMux
|
||||
|
||||
metrics *stateMetrics
|
||||
}
|
||||
|
||||
func NewState(p policy.Policy, opt settings.Settings, settings policy.StateSettings) (handler http.Handler, err error) {
|
||||
@@ -51,6 +53,7 @@ func NewState(p policy.Policy, opt settings.Settings, settings policy.StateSetti
|
||||
state.close = make(chan struct{})
|
||||
state.settings = settings
|
||||
state.opt = opt
|
||||
state.metrics = newMetrics()
|
||||
state.client = &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
@@ -214,7 +217,6 @@ func NewState(p policy.Policy, opt settings.Settings, settings policy.StateSetti
|
||||
}
|
||||
|
||||
for _, r := range p.Rules {
|
||||
|
||||
rule, err := NewRuleState(state, r, conditionReplacer, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("rule %s: %w", r.Name, err)
|
||||
|
Reference in New Issue
Block a user