Skip to content

Commit aae2e45

Browse files
committed
Add metric for login requests
Signed-off-by: ArthurSens <[email protected]>
1 parent 54b314b commit aae2e45

File tree

6 files changed

+44
-5
lines changed

6 files changed

+44
-5
lines changed

components/server/ee/src/monitoring-endpoint-ee.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,24 @@
55
*/
66

77
import * as express from 'express';
8-
import * as prometheusClient from 'prom-client';
98
import { WorkspaceHealthMonitoring } from './workspace/workspace-health-monitoring';
109
import { TraceContext } from '@gitpod/gitpod-protocol/lib/util/tracing';
1110
import * as request from 'request';
1211
import { Span } from 'opentracing';
1312
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
1413
import { injectable, inject } from 'inversify';
14+
import { register } from '../../src/prometheusMetrics';
1515

1616
@injectable()
1717
export class MonitoringEndpointsAppEE extends WorkspaceHealthMonitoring {
1818
@inject(WorkspaceHealthMonitoring) protected readonly workspaceHealthMonitoring: WorkspaceHealthMonitoring;
1919

2020
public create(): express.Application {
2121
const monApp = express();
22-
prometheusClient.collectDefaultMetrics({ timeout: 5000 });
23-
2422
monApp.get('/metrics', async (req, res) => {
2523
try {
26-
res.set('Content-Type', prometheusClient.register.contentType);
27-
res.end(await prometheusClient.register.metrics());
24+
res.set('Content-Type', register.contentType);
25+
res.end(register.metrics());
2826
} catch (ex) {
2927
res.status(500).end(ex);
3028
}

components/server/src/auth/authenticator.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { HostContextProvider } from './host-context-provider';
1515
import { AuthProvider, AuthFlow } from './auth-provider';
1616
import { TokenProvider } from '../user/token-provider';
1717
import { AuthProviderService } from './auth-provider-service';
18+
import { increaseLoginCounter } from '../../src/prometheusMetrics';
1819

1920
@injectable()
2021
export class Authenticator {
@@ -108,12 +109,14 @@ export class Authenticator {
108109
return;
109110
}
110111
if (!req.session) {
112+
increaseLoginCounter("failed", authProvider.info.host)
111113
log.info({ }, `No session.`, { req, 'login-flow': true });
112114
res.redirect(this.getSorryUrl(`No session found. Please refresh the browser.`));
113115
return;
114116
}
115117

116118
if (!authProvider.info.verified && !(await this.isInSetupMode())) {
119+
increaseLoginCounter("failed", authProvider.info.host)
117120
log.info({ sessionId: req.sessionID }, `Login with "${host}" is not permitted.`, { req, 'login-flow': true, ap: authProvider.info });
118121
res.redirect(this.getSorryUrl(`Login with "${host}" is not permitted.`));
119122
return;

components/server/src/auth/generic-auth-provider.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { UserService } from "../user/user-service";
2626
import { AuthProviderService } from './auth-provider-service';
2727
import { LoginCompletionHandler } from './login-completion-handler';
2828
import { TosFlow } from '../terms/tos-flow';
29+
import { increaseLoginCounter } from '../../src/prometheusMetrics';
2930

3031
/**
3132
* This is a generic implementation of OAuth2-based AuthProvider.
@@ -276,6 +277,8 @@ export class GenericAuthProvider implements AuthProvider {
276277

277278
// assert additional infomation is attached to current session
278279
if (!authFlow) {
280+
increaseLoginCounter("failed", this.host);
281+
279282
log.error(cxt, `(${strategyName}) No session found during auth callback.`, { request, clientInfo });
280283
response.redirect(this.getSorryUrl(`Please allow Cookies in your browser and try to log in again.`));
281284
return;
@@ -290,6 +293,8 @@ export class GenericAuthProvider implements AuthProvider {
290293
await AuthFlow.clear(request.session);
291294
await TosFlow.clear(request.session);
292295

296+
increaseLoginCounter("failed", this.host);
297+
293298
log.info(cxt, `(${strategyName}) Received OAuth2 error, thus redirecting to /sorry (${error})`, { ...defaultLogPayload, requestUrl: request.originalUrl });
294299
response.redirect(this.getSorryUrl(`OAuth2 error. (${error})`));
295300
return;
@@ -302,6 +307,8 @@ export class GenericAuthProvider implements AuthProvider {
302307
authenticate(request, response, next);
303308
})
304309
} catch (error) {
310+
increaseLoginCounter("failed", this.host);
311+
305312
response.redirect(this.getSorryUrl(`OAuth2 error. (${error})`));
306313
return;
307314
}
@@ -336,6 +343,9 @@ export class GenericAuthProvider implements AuthProvider {
336343
if (this.isOAuthError(err)) {
337344
message = 'OAuth Error. Please try again.'; // this is a 5xx response from authorization service
338345
}
346+
347+
increaseLoginCounter("failed", this.host);
348+
339349
log.error(context, `(${strategyName}) Redirect to /sorry from verify callback`, err, { ...defaultLogPayload, err });
340350
response.redirect(this.getSorryUrl(message));
341351
return;

components/server/src/auth/login-completion-handler.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { AuthFlow } from './auth-provider';
1414
import { HostContextProvider } from './host-context-provider';
1515
import { AuthProviderService } from './auth-provider-service';
1616
import { TosFlow } from '../terms/tos-flow';
17+
import { increaseLoginCounter } from '../../src/prometheusMetrics';
1718

1819
/**
1920
* The login completion handler pulls the strings between the OAuth2 flow, the ToS flow, and the session management.
@@ -44,6 +45,9 @@ export class LoginCompletionHandler {
4445
await TosFlow.clear(request.session);
4546
await AuthFlow.clear(request.session);
4647

48+
if (authHost) {
49+
increaseLoginCounter("failed", authHost)
50+
}
4751
log.error(logContext, `Redirect to /sorry on login`, err, { err, session: request.session });
4852
response.redirect(this.env.hostUrl.asSorry("Oops! Something went wrong during login.").toString());
4953
return;
@@ -72,6 +76,9 @@ export class LoginCompletionHandler {
7276
// Create Gitpod 🍪 before the redirect
7377
this.gitpodCookie.setCookie(response);
7478

79+
if (authHost) {
80+
increaseLoginCounter("succeeded", authHost)
81+
}
7582
response.redirect(returnTo);
7683
}
7784

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as prometheusClient from 'prom-client';
2+
3+
// Enable collection of default metrics.
4+
prometheusClient.collectDefaultMetrics({ timeout: 5000 });
5+
export const register = prometheusClient.register;
6+
7+
const loginCounter = new prometheusClient.Counter({
8+
name: 'gitpod_login_requests_total',
9+
help: 'Total amount of login requests',
10+
labelNames: ['status', 'auth_host'],
11+
registers: [prometheusClient.register]
12+
});
13+
14+
export function increaseLoginCounter(status: string, auth_host: string) {
15+
loginCounter.inc({
16+
status,
17+
auth_host,
18+
});
19+
}

components/server/src/user/user-controller.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { AuthFlow } from "../auth/auth-provider";
2626
import { LoginCompletionHandler } from "../auth/login-completion-handler";
2727
import { TosCookie } from "./tos-cookie";
2828
import { TosFlow } from "../terms/tos-flow";
29+
import { increaseLoginCounter } from '../../src/prometheusMetrics';
2930

3031
@injectable()
3132
export class UserController {
@@ -76,6 +77,7 @@ export class UserController {
7677
try {
7778
await saveSession(req);
7879
} catch (error) {
80+
increaseLoginCounter("failed", "unkown")
7981
log.error(`Login failed due to session save error; redirecting to /sorry`, { req, error, clientInfo });
8082
res.redirect(this.getSorryUrl("Login failed 🦄 Please try again"));
8183
}

0 commit comments

Comments
 (0)