mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-07 01:09:54 +08:00
chore(server): better internal error stack (#11009)
This commit is contained in:
@@ -150,6 +150,7 @@
|
|||||||
],
|
],
|
||||||
"env": {
|
"env": {
|
||||||
"NODE_ENV": "development",
|
"NODE_ENV": "development",
|
||||||
|
"AFFINE_ENV": "dev",
|
||||||
"AFFINE_SERVER_EXTERNAL_URL": "http://localhost:8080",
|
"AFFINE_SERVER_EXTERNAL_URL": "http://localhost:8080",
|
||||||
"DEBUG": "affine:*",
|
"DEBUG": "affine:*",
|
||||||
"FORCE_COLOR": true,
|
"FORCE_COLOR": true,
|
||||||
|
|||||||
@@ -114,6 +114,12 @@ export class UserFriendlyError extends Error {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get stacktrace() {
|
||||||
|
return this.name === 'internal_server_error'
|
||||||
|
? ((this.cause as Error)?.stack ?? super.stack)
|
||||||
|
: super.stack;
|
||||||
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return {
|
return {
|
||||||
status: this.status,
|
status: this.status,
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
import './config';
|
import './config';
|
||||||
|
|
||||||
import { STATUS_CODES } from 'node:http';
|
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
import type { ApolloDriverConfig } from '@nestjs/apollo';
|
import type { ApolloDriverConfig } from '@nestjs/apollo';
|
||||||
import { ApolloDriver } from '@nestjs/apollo';
|
import { ApolloDriver } from '@nestjs/apollo';
|
||||||
import { Global, HttpStatus, Module } from '@nestjs/common';
|
import { Global, Module } from '@nestjs/common';
|
||||||
import { GraphQLModule } from '@nestjs/graphql';
|
import { GraphQLModule } from '@nestjs/graphql';
|
||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import { GraphQLError } from 'graphql';
|
|
||||||
|
|
||||||
import { Config } from '../config';
|
import { Config } from '../config';
|
||||||
import { UserFriendlyError } from '../error';
|
import { mapAnyError } from '../nestjs/exception';
|
||||||
import { isGraphQLBadRequest, mapAnyError } from '../nestjs/exception';
|
|
||||||
import { GQLLoggerPlugin } from './logger-plugin';
|
import { GQLLoggerPlugin } from './logger-plugin';
|
||||||
|
|
||||||
export type GraphqlContext = {
|
export type GraphqlContext = {
|
||||||
@@ -52,39 +49,15 @@ export type GraphqlContext = {
|
|||||||
res,
|
res,
|
||||||
isAdminQuery: false,
|
isAdminQuery: false,
|
||||||
}),
|
}),
|
||||||
includeStacktraceInErrorResponses: !config.node.prod,
|
|
||||||
plugins: [new GQLLoggerPlugin()],
|
plugins: [new GQLLoggerPlugin()],
|
||||||
formatError: (formattedError, error) => {
|
formatError: (formattedError, error) => {
|
||||||
|
let ufe = mapAnyError(error);
|
||||||
|
|
||||||
// @ts-expect-error allow assign
|
// @ts-expect-error allow assign
|
||||||
formattedError.extensions ??= {};
|
formattedError.extensions = ufe.toJSON();
|
||||||
|
if (config.affine.canary) {
|
||||||
if (
|
formattedError.extensions.stacktrace = ufe.stacktrace;
|
||||||
error instanceof GraphQLError &&
|
|
||||||
error.originalError instanceof UserFriendlyError
|
|
||||||
) {
|
|
||||||
// @ts-expect-error allow assign
|
|
||||||
formattedError.extensions = error.originalError.toJSON();
|
|
||||||
formattedError.extensions.stacktrace = error.originalError.stack;
|
|
||||||
return formattedError;
|
|
||||||
} else if (
|
|
||||||
error instanceof GraphQLError &&
|
|
||||||
isGraphQLBadRequest(error)
|
|
||||||
) {
|
|
||||||
const err = mapAnyError(error);
|
|
||||||
// @ts-expect-error allow assign
|
|
||||||
formattedError.extensions = err.toJSON();
|
|
||||||
formattedError.extensions.stacktrace = err.stack;
|
|
||||||
return formattedError;
|
|
||||||
} else {
|
|
||||||
// @ts-expect-error allow assign
|
|
||||||
formattedError.message = 'Internal Server Error';
|
|
||||||
|
|
||||||
formattedError.extensions['status'] =
|
|
||||||
HttpStatus.INTERNAL_SERVER_ERROR;
|
|
||||||
formattedError.extensions['code'] =
|
|
||||||
STATUS_CODES[HttpStatus.INTERNAL_SERVER_ERROR];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return formattedError;
|
return formattedError;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { ConsoleLogger, Injectable, type LogLevel } from '@nestjs/common';
|
import { ConsoleLogger, Injectable, type LogLevel } from '@nestjs/common';
|
||||||
import { ClsServiceManager } from 'nestjs-cls';
|
import { ClsServiceManager } from 'nestjs-cls';
|
||||||
|
|
||||||
|
import { UserFriendlyError } from '../error';
|
||||||
|
|
||||||
// DO NOT use this Logger directly
|
// DO NOT use this Logger directly
|
||||||
// Use it via this way: `private readonly logger = new Logger(MyService.name)`
|
// Use it via this way: `private readonly logger = new Logger(MyService.name)`
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -20,7 +22,14 @@ export class AFFiNELogger extends ConsoleLogger {
|
|||||||
|
|
||||||
static formatStack(stackOrError?: Error | string | unknown) {
|
static formatStack(stackOrError?: Error | string | unknown) {
|
||||||
if (stackOrError instanceof Error) {
|
if (stackOrError instanceof Error) {
|
||||||
const err = stackOrError;
|
let err = stackOrError;
|
||||||
|
|
||||||
|
// most of the internal error are caught and created by `GlobalExceptionFilter`,
|
||||||
|
// and their error stack is helpless
|
||||||
|
if (err instanceof UserFriendlyError) {
|
||||||
|
return err.stacktrace;
|
||||||
|
}
|
||||||
|
|
||||||
let stack = err.stack ?? '';
|
let stack = err.stack ?? '';
|
||||||
if (err.cause instanceof Error && err.cause.stack) {
|
if (err.cause instanceof Error && err.cause.stack) {
|
||||||
stack += `\n\nCaused by:\n\n${err.cause.stack}`;
|
stack += `\n\nCaused by:\n\n${err.cause.stack}`;
|
||||||
|
|||||||
Reference in New Issue
Block a user