summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/mastodon
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2025-05-06 20:43:32 -0400
committerHazelnoot <acomputerdog@gmail.com>2025-05-08 11:23:20 -0400
commit282ef9e6734cf80f6a726345b1781054269b338b (patch)
treea86990259e30ec6cb95ab727b2b3c3fed92f9d97 /packages/backend/src/server/api/mastodon
parentminor refactor to ServerUtilityService.addMultipartFormDataContentType (diff)
downloadsharkey-282ef9e6734cf80f6a726345b1781054269b338b.tar.gz
sharkey-282ef9e6734cf80f6a726345b1781054269b338b.tar.bz2
sharkey-282ef9e6734cf80f6a726345b1781054269b338b.zip
split exception logging from error logging to simplify and improve mastodon errors
Diffstat (limited to 'packages/backend/src/server/api/mastodon')
-rw-r--r--packages/backend/src/server/api/mastodon/MastodonApiServerService.ts10
-rw-r--r--packages/backend/src/server/api/mastodon/MastodonLogger.ts81
2 files changed, 42 insertions, 49 deletions
diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts
index d95d75f12f..1b0ed2ce4e 100644
--- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts
+++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts
@@ -5,7 +5,7 @@
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
-import { getErrorData, getErrorStatus, MastodonLogger } from '@/server/api/mastodon/MastodonLogger.js';
+import { getErrorData, getErrorException, getErrorStatus, MastodonLogger } from '@/server/api/mastodon/MastodonLogger.js';
import { MastodonClientService } from '@/server/api/mastodon/MastodonClientService.js';
import { ApiAccountMastodon } from '@/server/api/mastodon/endpoints/account.js';
import { ApiAppsMastodon } from '@/server/api/mastodon/endpoints/apps.js';
@@ -47,16 +47,20 @@ export class MastodonApiServerService {
this.serverUtilityService.addFlattenedQueryType(fastify);
// Convert JS exceptions into error responses
- fastify.setErrorHandler((error, _, reply) => {
+ fastify.setErrorHandler((error, request, reply) => {
const data = getErrorData(error);
const status = getErrorStatus(error);
+ const exception = getErrorException(error);
+ if (exception) {
+ this.logger.exception(request, exception);
+ }
reply.code(status).send(data);
});
// Log error responses (including converted JSON exceptions)
fastify.addHook('onSend', (request, reply, payload, done) => {
- if (reply.statusCode >= 500 || (reply.statusCode >= 400 && this.logger.verbose)) {
+ if (reply.statusCode >= 400 && reply.statusCode <= 500) {
if (typeof(payload) === 'string' && String(reply.getHeader('content-type')).toLowerCase().includes('application/json')) {
const body = JSON.parse(payload);
const data = getErrorData(body);
diff --git a/packages/backend/src/server/api/mastodon/MastodonLogger.ts b/packages/backend/src/server/api/mastodon/MastodonLogger.ts
index 8d8f62bc0d..29d44918a3 100644
--- a/packages/backend/src/server/api/mastodon/MastodonLogger.ts
+++ b/packages/backend/src/server/api/mastodon/MastodonLogger.ts
@@ -25,13 +25,29 @@ export class MastodonLogger {
}
public error(request: FastifyRequest, error: MastodonError, status: number): void {
- const path = new URL(request.url, getBaseUrl(request)).pathname;
+ const path = getPath(request);
+
if (status >= 400 && status <= 499) { // Client errors
this.logger.debug(`Error in mastodon endpoint ${request.method} ${path}:`, error);
} else { // Server errors
this.logger.error(`Error in mastodon endpoint ${request.method} ${path}:`, error);
}
}
+
+ public exception(request: FastifyRequest, ex: Error): void {
+ const path = getPath(request);
+
+ // Exceptions are always server errors, and should therefore always be logged.
+ this.logger.error(`Error in mastodon endpoint ${request.method} ${path}:`, ex);
+ }
+}
+
+function getPath(request: FastifyRequest): string {
+ try {
+ return new URL(request.url, getBaseUrl(request)).pathname;
+ } catch {
+ return request.url;
+ }
}
// TODO move elsewhere
@@ -40,6 +56,17 @@ export interface MastodonError {
error_description?: string;
}
+export function getErrorException(error: unknown): Error | null {
+ if (error instanceof Error) {
+ // Axios errors are not exceptions - they're from the remote
+ if (!('response' in error) || !error.response || typeof (error.response) !== 'object') {
+ return error;
+ }
+ }
+
+ return null;
+}
+
export function getErrorData(error: unknown): MastodonError {
// Axios wraps errors from the backend
error = unpackAxiosError(error);
@@ -78,7 +105,10 @@ export function getErrorData(error: unknown): MastodonError {
}
}
- return convertUnknownError(error);
+ return {
+ error: 'INTERNAL_ERROR',
+ error_description: 'Internal error occurred. Please contact us if the error persists.',
+ };
}
function unpackAxiosError(error: unknown): unknown {
@@ -101,66 +131,25 @@ function unpackAxiosError(error: unknown): unknown {
}
function convertApiError(apiError: ApiError): MastodonError {
- const mastoError: MastodonError & Partial<ApiError> & { stack?: unknown, statusCode?: number } = {
- ...apiError,
+ return {
error: apiError.code,
error_description: apiError.message,
};
-
- delete mastoError.code;
- delete mastoError.stack;
- delete mastoError.message;
- delete mastoError.httpStatusCode;
-
- return mastoError;
}
function convertErrorMessageError(error: { error: string, message: string }): MastodonError {
- const mastoError: MastodonError & { stack?: unknown, message?: string, statusCode?: number } = {
- ...error,
+ return {
error: error.error,
error_description: error.message,
};
-
- delete mastoError.stack;
- delete mastoError.message;
- delete mastoError.statusCode;
-
- return mastoError;
-}
-
-function convertUnknownError(data: object = {}): MastodonError {
- const mastoError = Object.assign({}, data, {
- error: 'INTERNAL_ERROR',
- error_description: 'Internal error occurred. Please contact us if the error persists.',
- id: '5d37dbcb-891e-41ca-a3d6-e690c97775ac',
- kind: 'server',
- });
-
- if ('statusCode' in mastoError) {
- delete mastoError.statusCode;
- }
-
- if ('stack' in mastoError) {
- delete mastoError.stack;
- }
-
- return mastoError;
}
function convertGenericError(error: Error): MastodonError {
- const mastoError: MastodonError & Partial<Error> & { statusCode?: number } = {
+ return {
...error,
error: 'INTERNAL_ERROR',
error_description: String(error),
};
-
- delete mastoError.name;
- delete mastoError.message;
- delete mastoError.stack;
- delete mastoError.statusCode;
-
- return mastoError;
}
export function getErrorStatus(error: unknown): number {