Skip to content

Commit 9972d25

Browse files
geroplroboquat
authored andcommitted
[server] Trace ws rate limiter (429s) and access guards (403s)
1 parent c9a48a4 commit 9972d25

File tree

1 file changed

+22
-22
lines changed

1 file changed

+22
-22
lines changed

components/server/src/websocket/websocket-connection-manager.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -289,27 +289,9 @@ class GitpodJsonRpcProxyFactory<T extends object> extends JsonRpcProxyFactory<T>
289289
increaseApiCallUserCounter(method, "anonymous");
290290
}
291291

292-
try {
293-
await this.rateLimiter.consume(method);
294-
} catch (rlRejected) {
295-
if (rlRejected instanceof Error) {
296-
log.error("Unexpected error in the rate limiter", rlRejected);
297-
increaseApiCallCounter(method, 500);
298-
throw rlRejected;
299-
}
300-
log.warn(`Rate limiter prevents accessing method '${method}' of user '${this.rateLimiter.user} due to too many requests.`, rlRejected);
301-
increaseApiCallCounter(method, ErrorCodes.TOO_MANY_REQUESTS);
302-
throw new ResponseError(ErrorCodes.TOO_MANY_REQUESTS, "too many requests", { "Retry-After": String(Math.round(rlRejected.msBeforeNext / 1000)) || 1 });
303-
}
304-
305-
if (!this.accessGuard.canAccess(method)) {
306-
log.error(`Request ${method} is not allowed`, { method, args });
307-
increaseApiCallCounter(method, ErrorCodes.PERMISSION_DENIED);
308-
throw new ResponseError(ErrorCodes.PERMISSION_DENIED, "not allowed");
309-
}
310-
311292
const span = opentracing.globalTracer().startSpan(method);
312293
const ctx = { span };
294+
const userId = this.clientMetadata.userId;
313295
try {
314296
// generic tracing data
315297
TraceContext.addNestedTags(ctx, {
@@ -319,11 +301,29 @@ class GitpodJsonRpcProxyFactory<T extends object> extends JsonRpcProxyFactory<T>
319301
},
320302
});
321303
TraceContext.setOWI(ctx, {
322-
userId: this.clientMetadata.userId,
304+
userId,
323305
sessionId: this.clientMetadata.sessionId,
324306
});
325307
TraceContext.setJsonRPCMetadata(ctx, method);
326308

309+
// rate limiting
310+
try {
311+
await this.rateLimiter.consume(method);
312+
} catch (rlRejected) {
313+
if (rlRejected instanceof Error) {
314+
log.error({ userId }, "Unexpected error in the rate limiter", rlRejected);
315+
throw rlRejected;
316+
}
317+
log.warn({ userId }, "Rate limiter prevents accessing method due to too many requests.", rlRejected, { method });
318+
throw new ResponseError(ErrorCodes.TOO_MANY_REQUESTS, "too many requests", { "Retry-After": String(Math.round(rlRejected.msBeforeNext / 1000)) || 1 });
319+
}
320+
321+
// access guard
322+
if (!this.accessGuard.canAccess(method)) {
323+
// logging/tracing is done in 'catch' clause
324+
throw new ResponseError(ErrorCodes.PERMISSION_DENIED, `Request ${method} is not allowed`);
325+
}
326+
327327
// actual call
328328
const result = await this.target[method](ctx, ...args); // we can inject TraceContext here because of GitpodServerWithTracing
329329
increaseApiCallCounter(method, 200);
@@ -333,15 +333,15 @@ class GitpodJsonRpcProxyFactory<T extends object> extends JsonRpcProxyFactory<T>
333333
increaseApiCallCounter(method, e.code);
334334
TraceContext.setJsonRPCError(ctx, method, e);
335335

336-
log.info(`Request ${method} unsuccessful: ${e.code}/"${e.message}"`, { method, args });
336+
log.info({ userId }, `Request ${method} unsuccessful: ${e.code}/"${e.message}"`, { method, args });
337337
} else {
338338
TraceContext.setError(ctx, e); // this is a "real" error
339339

340340
const err = new ResponseError(500, "internal server error");
341341
increaseApiCallCounter(method, err.code);
342342
TraceContext.setJsonRPCError(ctx, method, err);
343343

344-
log.error(`Request ${method} failed with internal server error`, e, { method, args });
344+
log.error({ userId }, `Request ${method} failed with internal server error`, e, { method, args });
345345
}
346346
throw e;
347347
} finally {

0 commit comments

Comments
 (0)