From d4a83c1c6fa79fc37050987add6f26b83a5ebf65 Mon Sep 17 00:00:00 2001 From: X1a0t <405028157@qq.com> Date: Fri, 1 Sep 2023 12:05:35 +0800 Subject: [PATCH] feat: exception logger (#4059) --- apps/server/src/app.ts | 3 +- apps/server/src/graphql/logger-plugin.ts | 12 ------ .../server/src/middleware/exception-logger.ts | 38 +++++++++++++++++++ apps/server/src/modules/index.ts | 16 +++++++- 4 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 apps/server/src/middleware/exception-logger.ts diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index f85878e660..679c4981a2 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -3,7 +3,7 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { ConfigModule } from './config'; import { MetricsModule } from './metrics'; -import { BusinessModules } from './modules'; +import { BusinessModules, Providers } from './modules'; import { PrismaModule } from './prisma'; import { StorageModule } from './storage'; import { RateLimiterModule } from './throttler'; @@ -17,6 +17,7 @@ import { RateLimiterModule } from './throttler'; RateLimiterModule, ...BusinessModules, ], + providers: Providers, controllers: [AppController], }) export class AppModule {} diff --git a/apps/server/src/graphql/logger-plugin.ts b/apps/server/src/graphql/logger-plugin.ts index b59cdaf50d..ee7c6670a3 100644 --- a/apps/server/src/graphql/logger-plugin.ts +++ b/apps/server/src/graphql/logger-plugin.ts @@ -7,7 +7,6 @@ import { Plugin } from '@nestjs/apollo'; import { Logger } from '@nestjs/common'; import { Response } from 'express'; -import { OPERATION_NAME, REQUEST_ID } from '../constants'; import { Metrics } from '../metrics/metrics'; import { ReqContext } from '../types'; @@ -22,19 +21,10 @@ export class GQLLoggerPlugin implements ApolloServerPlugin { ): Promise>> { const res = reqContext.contextValue.req.res as Response; const operation = reqContext.request.operationName; - const headers = reqContext.request.http?.headers; - const requestId = headers - ? headers.get(`${REQUEST_ID}`) - : 'Unknown Request ID'; - const operationName = headers - ? headers.get(`${OPERATION_NAME}`) - : 'Unknown Operation Name'; this.metrics.gqlRequest(1, { operation }); const timer = this.metrics.gqlTimer({ operation }); - const requestInfo = `${REQUEST_ID}: ${requestId}, ${OPERATION_NAME}: ${operationName}`; - return Promise.resolve({ willSendResponse: () => { const costInMilliseconds = timer() * 1000; @@ -42,7 +32,6 @@ export class GQLLoggerPlugin implements ApolloServerPlugin { 'Server-Timing', `gql;dur=${costInMilliseconds};desc="GraphQL"` ); - this.logger.log(requestInfo); return Promise.resolve(); }, didEncounterErrors: () => { @@ -52,7 +41,6 @@ export class GQLLoggerPlugin implements ApolloServerPlugin { 'Server-Timing', `gql;dur=${costInMilliseconds};desc="GraphQL ${operation}"` ); - this.logger.error(`${requestInfo}, query: ${reqContext.request.query}`); return Promise.resolve(); }, }); diff --git a/apps/server/src/middleware/exception-logger.ts b/apps/server/src/middleware/exception-logger.ts new file mode 100644 index 0000000000..79497acfdd --- /dev/null +++ b/apps/server/src/middleware/exception-logger.ts @@ -0,0 +1,38 @@ +import { + ArgumentsHost, + Catch, + ExceptionFilter, + HttpException, + Logger, +} from '@nestjs/common'; +import { Request, Response } from 'express'; + +import { REQUEST_ID } from '../constants'; + +@Catch(HttpException) +export class ExceptionLogger implements ExceptionFilter { + private logger = new Logger('ExceptionLogger'); + + catch(exception: Error, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const request = ctx.getRequest(); + const requestId = request?.header(REQUEST_ID); + this.logger.error( + new Error( + `${requestId ? `requestId-${requestId}:` : ''}${exception.message}`, + { cause: exception } + ), + exception.stack + ); + + const response = ctx.getResponse(); + if (exception instanceof HttpException) { + response.json(exception.getResponse()); + } else { + response.status(500).json({ + message: exception.message, + statusCode: 500, + }); + } + } +} diff --git a/apps/server/src/modules/index.ts b/apps/server/src/modules/index.ts index c11e3428b1..10b0f6fead 100644 --- a/apps/server/src/modules/index.ts +++ b/apps/server/src/modules/index.ts @@ -1,6 +1,8 @@ -import { DynamicModule, Type } from '@nestjs/common'; +import { DynamicModule, Provider, Type } from '@nestjs/common'; +import { APP_FILTER } from '@nestjs/core'; import { GqlModule } from '../graphql.module'; +import { ExceptionLogger } from '../middleware/exception-logger'; import { AuthModule } from './auth'; import { DocModule } from './doc'; import { SyncModule } from './sync'; @@ -8,6 +10,7 @@ import { UsersModule } from './users'; import { WorkspaceModule } from './workspaces'; const { SERVER_FLAVOR } = process.env; +const { NODE_ENV } = process.env; const BusinessModules: (Type | DynamicModule)[] = []; @@ -37,4 +40,13 @@ switch (SERVER_FLAVOR) { break; } -export { BusinessModules }; +const Providers: Provider[] = []; + +if (NODE_ENV !== 'test') { + Providers.push({ + provide: APP_FILTER, + useClass: ExceptionLogger, + }); +} + +export { BusinessModules, Providers };