Skip to content

Commit 3401d3b

Browse files
authored
feat: Export metrics to track number of users (#20801) (#23343)
Signed-off-by: Sathiya Narayanan Venkatesan <[email protected]> Signed-off-by: sathiya06 <[email protected]>
1 parent 0a0176f commit 3401d3b

File tree

5 files changed

+54
-2
lines changed

5 files changed

+54
-2
lines changed

docs/operator-manual/metrics.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ argocd_cluster_labels{label_environment="production",label_team_name="team3",nam
210210
Metrics about API Server API request and response activity (request totals, response codes, etc...).
211211
Scraped at the `argocd-server-metrics:8083/metrics` endpoint.
212212

213-
| Metric | Type | Description |
214-
| ------------------------------------------------- | :-------: | ------------------------------------------------------------------------------------------- |
213+
| Metric | Type | Description
214+
|---------------------------------------------------|:---------:|---------------------------------------------------------------------------------------------|
215+
| `argocd_login_request_total` | counter | Number of login requests. |
215216
| `argocd_redis_request_duration` | histogram | Redis requests duration. |
216217
| `argocd_redis_request_total` | counter | Number of Kubernetes requests executed during application reconciliation. |
217218
| `grpc_server_handled_total` | counter | Total number of RPCs completed on the server, regardless of success or failure. |

server/metrics/metrics.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type MetricsServer struct {
2020
redisRequestHistogram *prometheus.HistogramVec
2121
extensionRequestCounter *prometheus.CounterVec
2222
extensionRequestDuration *prometheus.HistogramVec
23+
loginRequestCounter *prometheus.CounterVec
2324
}
2425

2526
var (
@@ -53,6 +54,13 @@ var (
5354
},
5455
[]string{"extension"},
5556
)
57+
loginRequestCounter = prometheus.NewCounterVec(
58+
prometheus.CounterOpts{
59+
Name: "argocd_login_request_total",
60+
Help: "Number of login requests to the Argo CD API server.",
61+
},
62+
[]string{"status"},
63+
)
5664
argoVersion = prometheus.NewGaugeVec(
5765
prometheus.GaugeOpts{
5866
Name: "argocd_info",
@@ -78,6 +86,7 @@ func NewMetricsServer(host string, port int) *MetricsServer {
7886
registry.MustRegister(redisRequestHistogram)
7987
registry.MustRegister(extensionRequestCounter)
8088
registry.MustRegister(extensionRequestDuration)
89+
registry.MustRegister(loginRequestCounter)
8190
registry.MustRegister(argoVersion)
8291

8392
kubectl.RegisterWithClientGo()
@@ -92,6 +101,7 @@ func NewMetricsServer(host string, port int) *MetricsServer {
92101
redisRequestHistogram: redisRequestHistogram,
93102
extensionRequestCounter: extensionRequestCounter,
94103
extensionRequestDuration: extensionRequestDuration,
104+
loginRequestCounter: loginRequestCounter,
95105
}
96106
}
97107

@@ -111,3 +121,9 @@ func (m *MetricsServer) IncExtensionRequestCounter(extension string, status int)
111121
func (m *MetricsServer) ObserveExtensionRequestDuration(extension string, duration time.Duration) {
112122
m.extensionRequestDuration.WithLabelValues(extension).Observe(duration.Seconds())
113123
}
124+
125+
// IncLoginRequestCounter increments the login request counter with the given status
126+
// status can be "success" or "failure"
127+
func (m *MetricsServer) IncLoginRequestCounter(status string) {
128+
m.loginRequestCounter.WithLabelValues(status).Inc()
129+
}

server/server.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,9 @@ func (server *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) {
573573
server.userStateStorage.Init(ctx)
574574

575575
svcSet := newArgoCDServiceSet(server)
576+
if server.sessionMgr != nil {
577+
server.sessionMgr.CollectMetrics(metricsServ)
578+
}
576579
server.serviceSet = svcSet
577580
grpcS, appResourceTreeFn := server.newGRPCServer()
578581
grpcWebS := grpcweb.WrapServer(grpcS)

server/session/session.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ type Authenticator interface {
2929
Authenticate(ctx context.Context) (context.Context, error)
3030
}
3131

32+
const (
33+
success = "success"
34+
failure = "failure"
35+
)
36+
3237
// NewServer returns a new instance of the Session service
3338
func NewServer(mgr *sessionmgr.SessionManager, settingsMgr *settings.SettingsManager, authenticator Authenticator, policyEnf *rbacpolicy.RBACPolicyEnforcer, rateLimiter func() (utilio.Closer, error)) *Server {
3439
return &Server{mgr, settingsMgr, authenticator, policyEnf, rateLimiter}
@@ -40,36 +45,44 @@ func (s *Server) Create(_ context.Context, q *session.SessionCreateRequest) (*se
4045
if s.limitLoginAttempts != nil {
4146
closer, err := s.limitLoginAttempts()
4247
if err != nil {
48+
s.mgr.IncLoginRequestCounter(failure)
4349
return nil, err
4450
}
4551
defer utilio.Close(closer)
4652
}
4753

4854
if q.Token != "" {
55+
s.mgr.IncLoginRequestCounter(failure)
4956
return nil, status.Errorf(codes.Unauthenticated, "token-based session creation no longer supported. please upgrade argocd cli to v0.7+")
5057
}
5158
if q.Username == "" || q.Password == "" {
59+
s.mgr.IncLoginRequestCounter(failure)
5260
return nil, status.Errorf(codes.Unauthenticated, "no credentials supplied")
5361
}
5462
err := s.mgr.VerifyUsernamePassword(q.Username, q.Password)
5563
if err != nil {
64+
s.mgr.IncLoginRequestCounter(failure)
5665
return nil, err
5766
}
5867
uniqueId, err := uuid.NewRandom()
5968
if err != nil {
69+
s.mgr.IncLoginRequestCounter(failure)
6070
return nil, err
6171
}
6272
argoCDSettings, err := s.settingsMgr.GetSettings()
6373
if err != nil {
74+
s.mgr.IncLoginRequestCounter(failure)
6475
return nil, err
6576
}
6677
jwtToken, err := s.mgr.Create(
6778
fmt.Sprintf("%s:%s", q.Username, settings.AccountCapabilityLogin),
6879
int64(argoCDSettings.UserSessionDuration.Seconds()),
6980
uniqueId.String())
7081
if err != nil {
82+
s.mgr.IncLoginRequestCounter(failure)
7183
return nil, err
7284
}
85+
s.mgr.IncLoginRequestCounter(success)
7386
return &session.SessionResponse{Token: jwtToken}, nil
7487
}
7588

util/session/sessionmanager.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type SessionManager struct {
4343
sleep func(d time.Duration)
4444
verificationDelayNoiseEnabled bool
4545
failedLock sync.RWMutex
46+
metricsRegistry MetricsRegistry
4647
}
4748

4849
// LoginAttempts is a timestamped counter for failed login attempts
@@ -53,6 +54,10 @@ type LoginAttempts struct {
5354
FailCount int `json:"failCount"`
5455
}
5556

57+
type MetricsRegistry interface {
58+
IncLoginRequestCounter(status string)
59+
}
60+
5661
const (
5762
// SessionManagerClaimsIssuer fills the "iss" field of the token.
5863
SessionManagerClaimsIssuer = "argocd"
@@ -172,6 +177,20 @@ func (mgr *SessionManager) Create(subject string, secondsBeforeExpiry int64, id
172177
return mgr.signClaims(claims)
173178
}
174179

180+
func (mgr *SessionManager) CollectMetrics(registry MetricsRegistry) {
181+
mgr.metricsRegistry = registry
182+
if mgr.metricsRegistry == nil {
183+
log.Warn("Metrics registry is not set, metrics will not be collected")
184+
return
185+
}
186+
}
187+
188+
func (mgr *SessionManager) IncLoginRequestCounter(status string) {
189+
if mgr.metricsRegistry != nil {
190+
mgr.metricsRegistry.IncLoginRequestCounter(status)
191+
}
192+
}
193+
175194
func (mgr *SessionManager) signClaims(claims jwt.Claims) (string, error) {
176195
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
177196
settings, err := mgr.settingsMgr.GetSettings()

0 commit comments

Comments
 (0)