mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-25 18:26:05 +08:00
fix: logger filter should pass graphql context (#4209)
This commit is contained in:
@@ -4,10 +4,13 @@ import {
|
|||||||
ExceptionFilter,
|
ExceptionFilter,
|
||||||
HttpException,
|
HttpException,
|
||||||
Logger,
|
Logger,
|
||||||
|
NotFoundException,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { GqlContextType } from '@nestjs/graphql';
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
|
|
||||||
import { REQUEST_ID } from '../constants';
|
import { REQUEST_ID } from '../constants';
|
||||||
|
const TrivialExceptions = [NotFoundException];
|
||||||
|
|
||||||
@Catch()
|
@Catch()
|
||||||
export class ExceptionLogger implements ExceptionFilter {
|
export class ExceptionLogger implements ExceptionFilter {
|
||||||
@@ -16,15 +19,26 @@ export class ExceptionLogger implements ExceptionFilter {
|
|||||||
catch(exception: Error, host: ArgumentsHost) {
|
catch(exception: Error, host: ArgumentsHost) {
|
||||||
// with useGlobalFilters, the context is always HTTP
|
// with useGlobalFilters, the context is always HTTP
|
||||||
const ctx = host.switchToHttp();
|
const ctx = host.switchToHttp();
|
||||||
|
|
||||||
const request = ctx.getRequest<Request>();
|
const request = ctx.getRequest<Request>();
|
||||||
const requestId = request?.header(REQUEST_ID);
|
const requestId = request?.header(REQUEST_ID);
|
||||||
|
|
||||||
|
const shouldVerboseLog = !TrivialExceptions.some(
|
||||||
|
e => exception instanceof e
|
||||||
|
);
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
new Error(
|
new Error(
|
||||||
`${requestId ? `requestId-${requestId}:` : ''}${exception.message}`,
|
`${requestId ? `requestId-${requestId}:` : ''}${exception.message}`,
|
||||||
{ cause: exception }
|
{ cause: exception }
|
||||||
),
|
)
|
||||||
exception.stack
|
|
||||||
);
|
);
|
||||||
|
if (shouldVerboseLog) {
|
||||||
|
this.logger.error(exception.stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host.getType<GqlContextType>() === 'graphql') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const response = ctx.getResponse<Response>();
|
const response = ctx.getResponse<Response>();
|
||||||
if (exception instanceof HttpException) {
|
if (exception instanceof HttpException) {
|
||||||
|
|||||||
87
apps/server/src/tests/exception-logger.e2e.ts
Normal file
87
apps/server/src/tests/exception-logger.e2e.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { Controller, Get, INestApplication } from '@nestjs/common';
|
||||||
|
import { Test } from '@nestjs/testing';
|
||||||
|
import test from 'ava';
|
||||||
|
// @ts-expect-error graphql-upload is not typed
|
||||||
|
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs';
|
||||||
|
import request from 'supertest';
|
||||||
|
|
||||||
|
import { AppModule } from '../app';
|
||||||
|
import { ExceptionLogger } from '../middleware/exception-logger';
|
||||||
|
import { PrismaService } from '../prisma';
|
||||||
|
|
||||||
|
const gql = '/graphql';
|
||||||
|
const rest = '/rest';
|
||||||
|
|
||||||
|
let app: INestApplication;
|
||||||
|
|
||||||
|
class FakePrisma {
|
||||||
|
get workspace() {
|
||||||
|
return {
|
||||||
|
async findUnique() {
|
||||||
|
throw Error('exception from graphql');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Controller('rest')
|
||||||
|
export class MockController {
|
||||||
|
@Get()
|
||||||
|
test(): string {
|
||||||
|
throw new Error('exception from rest api');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test.beforeEach(async () => {
|
||||||
|
const module = await Test.createTestingModule({
|
||||||
|
imports: [AppModule],
|
||||||
|
controllers: [MockController],
|
||||||
|
})
|
||||||
|
.overrideProvider(PrismaService)
|
||||||
|
.useClass(FakePrisma)
|
||||||
|
.compile();
|
||||||
|
app = module.createNestApplication({
|
||||||
|
cors: true,
|
||||||
|
bodyParser: true,
|
||||||
|
});
|
||||||
|
app.useGlobalFilters(new ExceptionLogger());
|
||||||
|
app.use(
|
||||||
|
graphqlUploadExpress({
|
||||||
|
maxFileSize: 10 * 1024 * 1024,
|
||||||
|
maxFiles: 5,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
await app.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async () => {
|
||||||
|
await app.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should get response from graphql', async t => {
|
||||||
|
const id = 'workspace';
|
||||||
|
|
||||||
|
const response = await request(app.getHttpServer())
|
||||||
|
.post(gql)
|
||||||
|
.send({
|
||||||
|
name: 'getPublicWorkspace',
|
||||||
|
query: `
|
||||||
|
query getPublicWorkspace($id: String!) {
|
||||||
|
publicWorkspace(id: $id) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
t.is(response.status, 200);
|
||||||
|
t.is(response.body.errors[0].message, 'exception from graphql');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should get response from rest api', async t => {
|
||||||
|
const response = await request(app.getHttpServer()).get(rest);
|
||||||
|
|
||||||
|
t.is(response.status, 500);
|
||||||
|
t.is(response.body.error, 'exception from rest api');
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user