refactor(server): simplify metrics creation and usage (#5115)

This commit is contained in:
liuyi
2023-11-29 08:05:08 +00:00
parent 7a7cbc45d7
commit 89f267a3fe
13 changed files with 341 additions and 90 deletions

View File

@@ -89,12 +89,13 @@ export class NextAuthController {
res.redirect(`/signin${query}`);
return;
}
metrics().authCounter.add(1);
const [action, providerId] = req.url // start with request url
.slice(BASE_URL.length) // make relative to baseUrl
.replace(/\?.*/, '') // remove query part, use only path part
.split('/') as [AuthAction, string]; // as array of strings;
metrics.auth.counter('call_counter').add(1, { action, providerId });
const credentialsSignIn =
req.method === 'POST' && providerId === 'credentials';
let userId: string | undefined;
@@ -126,7 +127,9 @@ export class NextAuthController {
const options = this.nextAuthOptions;
if (req.method === 'POST' && action === 'session') {
if (typeof req.body !== 'object' || typeof req.body.data !== 'object') {
metrics().authFailCounter.add(1, { reason: 'invalid_session_data' });
metrics.auth
.counter('call_fails_counter')
.add(1, { reason: 'invalid_session_data' });
throw new BadRequestException(`Invalid new session data`);
}
const user = await this.updateSession(req, req.body.data);
@@ -209,9 +212,10 @@ export class NextAuthController {
if (redirect?.endsWith('api/auth/error?error=AccessDenied')) {
this.logger.log(`Early access redirect headers: ${req.headers}`);
metrics().authFailCounter.add(1, {
reason: 'no_early_access_permission',
});
metrics.auth
.counter('call_fails_counter')
.add(1, { reason: 'no_early_access_permission' });
if (
!req.headers?.referer ||
checkUrlOrigin(req.headers.referer, 'https://accounts.google.com')

View File

@@ -68,7 +68,11 @@ export class DocHistoryManager {
// safe to ignore
// only happens when duplicated history record created in multi processes
});
metrics().docHistoryCounter.add(1, {});
metrics.doc
.counter('history_created_counter', {
description: 'How many times the snapshot history created',
})
.add(1);
this.logger.log(
`History created for ${snapshot.id} in workspace ${snapshot.workspaceId}.`
);
@@ -182,7 +186,11 @@ export class DocHistoryManager {
// which is not the solution in CRDT.
// let user revert in client and update the data in sync system
// `await this.db.snapshot.update();`
metrics().docRecoverCounter.add(1, {});
metrics.doc
.counter('history_recovered_counter', {
description: 'How many times history recovered request happened',
})
.add(1);
return history.timestamp;
}

View File

@@ -125,13 +125,13 @@ export class DocManager implements OnModuleInit, OnModuleDestroy {
this.config.doc.manager.experimentalMergeWithJwstCodec &&
updates.length < 100 /* avoid overloading */
) {
metrics().jwstCodecMerge.add(1);
metrics.jwst.counter('codec_merge_counter').add(1);
const yjsResult = Buffer.from(encodeStateAsUpdate(doc));
let log = false;
try {
const jwstResult = jwstMergeUpdates(updates);
if (!compare(yjsResult, jwstResult)) {
metrics().jwstCodecDidnotMatch.add(1);
metrics.jwst.counter('codec_not_match').add(1);
this.logger.warn(
`jwst codec result doesn't match yjs codec result for: ${guid}`
);
@@ -142,7 +142,7 @@ export class DocManager implements OnModuleInit, OnModuleDestroy {
}
}
} catch (e) {
metrics().jwstCodecFail.add(1);
metrics.jwst.counter('codec_fails_counter').add(1);
this.logger.warn(`jwst apply update failed for ${guid}: ${e}`);
log = true;
} finally {

View File

@@ -45,6 +45,7 @@ export const GatewayErrorWrapper = (): MethodDecorator => {
try {
result = originalMethod.apply(this, args);
} catch (e) {
metrics.socketio.counter('unhandled_errors').add(1);
return {
error: new InternalError(e as Error),
};
@@ -52,6 +53,7 @@ export const GatewayErrorWrapper = (): MethodDecorator => {
if (result instanceof Promise) {
return result.catch(e => {
metrics.socketio.counter('unhandled_errors').add(1);
return {
error: new InternalError(e),
};
@@ -68,7 +70,7 @@ export const GatewayErrorWrapper = (): MethodDecorator => {
const SubscribeMessage = (event: string) =>
applyDecorators(
GatewayErrorWrapper(),
CallTimer('socket_io_event_duration', { event }),
CallTimer('socketio', 'event_duration', { event }),
RawSubscribeMessage(event)
);
@@ -104,12 +106,12 @@ export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
handleConnection() {
this.connectionCount++;
metrics().socketIOConnectionGauge(this.connectionCount);
metrics.socketio.gauge('realtime_connections').record(this.connectionCount);
}
handleDisconnect() {
this.connectionCount--;
metrics().socketIOConnectionGauge(this.connectionCount);
metrics.socketio.gauge('realtime_connections').record(this.connectionCount);
}
@Auth()

View File

@@ -34,7 +34,7 @@ export class WorkspacesController {
//
// NOTE: because graphql can't represent a File, so we have to use REST API to get blob
@Get('/:id/blobs/:name')
@CallTimer('doc_controller', { method: 'get_blob' })
@CallTimer('controllers', 'workspace_get_blob')
async blob(
@Param('id') workspaceId: string,
@Param('name') name: string,
@@ -59,7 +59,7 @@ export class WorkspacesController {
@Get('/:id/docs/:guid')
@Auth()
@Publicable()
@CallTimer('doc_controller', { method: 'get_doc' })
@CallTimer('controllers', 'workspace_get_doc')
async doc(
@CurrentUser() user: UserType | undefined,
@Param('id') ws: string,
@@ -106,7 +106,7 @@ export class WorkspacesController {
@Get('/:id/docs/:guid/histories/:timestamp')
@Auth()
@CallTimer('doc_controller', { method: 'get_history' })
@CallTimer('controllers', 'workspace_get_history')
async history(
@CurrentUser() user: UserType,
@Param('id') ws: string,