de-duplicate mastodon API logging
This commit is contained in:
parent
03edc33424
commit
da25595ba3
10 changed files with 827 additions and 1229 deletions
|
|
@ -3,37 +3,137 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import Logger, { Data } from '@/logger.js';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import Logger from '@/logger.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import { ApiError } from '@/server/api/error.js';
|
||||
import { EnvService } from '@/core/EnvService.js';
|
||||
import { FastifyRequest } from 'fastify';
|
||||
|
||||
@Injectable()
|
||||
export class MastodonLogger {
|
||||
public readonly logger: Logger;
|
||||
|
||||
constructor(loggerService: LoggerService) {
|
||||
constructor(
|
||||
@Inject(EnvService)
|
||||
private readonly envService: EnvService,
|
||||
|
||||
loggerService: LoggerService,
|
||||
) {
|
||||
this.logger = loggerService.getLogger('masto-api');
|
||||
}
|
||||
|
||||
public error(endpoint: string, error: Data): void {
|
||||
this.logger.error(`Error in mastodon API endpoint ${endpoint}:`, error);
|
||||
public error(request: FastifyRequest, error: MastodonError, status: number): void {
|
||||
if ((status < 400 && status > 499) || this.envService.env.NODE_ENV === 'development') {
|
||||
this.logger.error(`Error in mastodon endpoint ${request.method} ${request.url}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getErrorData(error: unknown): Data {
|
||||
if (error == null) return {};
|
||||
if (typeof(error) === 'string') return error;
|
||||
if (typeof(error) === 'object') {
|
||||
// TODO move elsewhere
|
||||
export interface MastodonError {
|
||||
error: string;
|
||||
error_description: string;
|
||||
}
|
||||
|
||||
export function getErrorData(error: unknown): MastodonError {
|
||||
if (error && typeof(error) === 'object') {
|
||||
// AxiosError, comes from the backend
|
||||
if ('response' in error) {
|
||||
if (typeof(error.response) === 'object' && error.response) {
|
||||
if ('data' in error.response) {
|
||||
if (typeof(error.response.data) === 'object' && error.response.data) {
|
||||
return error.response.data as Record<string, unknown>;
|
||||
if ('error' in error.response.data) {
|
||||
if (typeof(error.response.data.error) === 'object' && error.response.data.error) {
|
||||
if ('code' in error.response.data.error) {
|
||||
if (typeof(error.response.data.error.code) === 'string') {
|
||||
return convertApiError(error.response.data.error as ApiError);
|
||||
}
|
||||
}
|
||||
|
||||
return convertUnknownError(error.response.data.error);
|
||||
}
|
||||
}
|
||||
|
||||
return convertUnknownError(error.response.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No data - this is a fallback to avoid leaking request/response details in the error
|
||||
return convertUnknownError();
|
||||
}
|
||||
|
||||
if (error instanceof ApiError) {
|
||||
return convertApiError(error);
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
return convertGenericError(error);
|
||||
}
|
||||
|
||||
return convertUnknownError(error);
|
||||
}
|
||||
|
||||
return {
|
||||
error: 'UNKNOWN_ERROR',
|
||||
error_description: String(error),
|
||||
};
|
||||
}
|
||||
|
||||
function convertApiError(apiError: ApiError): MastodonError {
|
||||
const mastoError: MastodonError & Partial<ApiError> = {
|
||||
error: apiError.code,
|
||||
error_description: apiError.message,
|
||||
...apiError,
|
||||
};
|
||||
|
||||
delete mastoError.code;
|
||||
delete mastoError.message;
|
||||
|
||||
return mastoError;
|
||||
}
|
||||
|
||||
function convertUnknownError(data: object = {}): MastodonError {
|
||||
return 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',
|
||||
});
|
||||
}
|
||||
|
||||
function convertGenericError(error: Error): MastodonError {
|
||||
const mastoError: MastodonError & Partial<Error> = {
|
||||
error: 'INTERNAL_ERROR',
|
||||
error_description: String(error),
|
||||
...error,
|
||||
};
|
||||
|
||||
delete mastoError.name;
|
||||
delete mastoError.message;
|
||||
delete mastoError.stack;
|
||||
|
||||
return mastoError;
|
||||
}
|
||||
|
||||
export function getErrorStatus(error: unknown): number {
|
||||
// AxiosError, comes from the backend
|
||||
if (typeof(error) === 'object' && error) {
|
||||
if ('response' in error) {
|
||||
if (typeof (error.response) === 'object' && error.response) {
|
||||
if ('status' in error.response) {
|
||||
if (typeof(error.response.status) === 'number') {
|
||||
return error.response.status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return error as Record<string, unknown>;
|
||||
}
|
||||
return { error };
|
||||
|
||||
if (error instanceof ApiError && error.httpStatusCode) {
|
||||
return error.httpStatusCode;
|
||||
}
|
||||
|
||||
return 500;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue