Skip to content

Commit

Permalink
feat: error logging
Browse files Browse the repository at this point in the history
  • Loading branch information
froid1911 authored and acaldas committed Apr 2, 2024
1 parent 9e815ec commit b6fd264
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 63 deletions.
3 changes: 2 additions & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@
"body-parser": "^1.20.2",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"document-drive": "1.0.0-alpha.24",
"document-drive": "1.0.0-alpha.25",
"document-model": "^1.0.35",
"document-model-libs": "^1.17.1",
"dotenv": "^16.4.5",
"ethers": "^5.7.2",
"express": "^4.19.2",
"express-async-errors": "^3.1.1",
"graphql": "^16.8.1",
"graphql-middleware": "^6.1.35",
"graphql-playground-html": "^1.6.30",
Expand Down
19 changes: 15 additions & 4 deletions api/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions api/src/errors/BadRequestError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { CustomError } from "./CustomError";

export default class BadRequestError extends CustomError {
private static readonly _statusCode = 400;
private readonly _code: number;
private readonly _logging: boolean;
private readonly _context: { [key: string]: any };

constructor(params?: {code?: number, message?: string, logging?: boolean, context?: { [key: string]: any }}) {
const { code, message, logging } = params || {};

super(message || "Bad request");
this._code = code || BadRequestError._statusCode;
this._logging = logging || false;
this._context = params?.context || {};

// Only because we are extending a built in class
Object.setPrototypeOf(this, BadRequestError.prototype);
}

get errors() {
return [{ message: this.message, context: this._context }];
}

get statusCode() {
return this._code;
}

get logging() {
return this._logging;
}
}
17 changes: 17 additions & 0 deletions api/src/errors/CustomError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export type CustomErrorContent = {
message: string,
context?: { [key: string]: any }
};

export abstract class CustomError extends Error {
abstract readonly statusCode: number;
abstract readonly errors: CustomErrorContent[];
abstract readonly logging: boolean;

constructor(message: string) {
super(message);

// Only because we are extending a built in class
Object.setPrototypeOf(this, CustomError.prototype);
}
}
32 changes: 32 additions & 0 deletions api/src/errors/DocumentDriveError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { CustomError } from "./CustomError";

export default class DocumentDriveError extends CustomError {
private static readonly _statusCode = 400;
private readonly _code: number;
private readonly _logging: boolean;
private readonly _context: { [key: string]: any };

constructor(params?: { code?: number, message?: string, logging?: boolean, context?: { [key: string]: any } }) {
const { code, message, logging } = params || {};

super(message || "Bad request");
this._code = code || DocumentDriveError._statusCode;
this._logging = logging || false;
this._context = params?.context || {};

// Only because we are extending a built in class
Object.setPrototypeOf(this, DocumentDriveError.prototype);
}

get errors() {
return [{ message: this.message, context: this._context }];
}

get statusCode() {
return this._code;
}

get logging() {
return this._logging;
}
}
5 changes: 4 additions & 1 deletion api/src/graphql/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import cors from 'cors';
import { PORT } from '../../env';
import { schemaWithMiddleware as indexSchema } from './index/schema';
import { schemaWithMiddleware as driveSchema } from './drive/schema';
import { Context as IndexContext, createContext as createIndexContext } from './index/context';
import { Context, Context as IndexContext, createContext as createIndexContext } from './index/context';
import { Context as DriveContext, createContext as createDriveContext } from './drive/context';
import { getChildLogger } from '../../logger';
import "express-async-errors";
import { errorHandler } from '../../middleware/errors';

const logger = getChildLogger({ msgPrefix: 'SERVER' });

Expand Down Expand Up @@ -72,6 +74,7 @@ export const startServer = async (
}),
);

app.use(errorHandler);
return httpServer.listen({ port: PORT }, () => {
logger.info(`Running on ${PORT}`);
});
Expand Down
15 changes: 15 additions & 0 deletions api/src/middleware/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { NextFunction, Request, Response } from "express";
import { getChildLogger } from "../logger";
import { CustomError } from "../errors/CustomError";

const logger = getChildLogger({ msgPrefix: 'Generic Error Handler', });

export const errorHandler = (err: Error, req: Request, res: Response, next: NextFunction) => {
err.cause = err.cause || 'Unknown';
logger.error({
msg: err.message,
});

console.log("TEST TEST TEST")
res.status(500).send({ errors: err.message });
};
109 changes: 62 additions & 47 deletions api/src/modules/document-drive/drive-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import stringify from 'json-stringify-deterministic';
import { getChildLogger } from '../../logger';
import { Context } from '../../graphql/server/drive/context';
import { DocumentDriveAction } from 'document-model-libs/document-drive';
import DocumentDriveError from '../../errors/DocumentDriveError';

const logger = getChildLogger({ msgPrefix: 'Drive Resolver' });

Expand Down Expand Up @@ -234,9 +235,8 @@ export const getDrive = queryField('drive', {
try {
const drive = await ctx.prisma.document.getDrive(ctx.driveId ?? '1');
return drive;
} catch (e) {
logger.error(e);
return null;
} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to get drive", logging: true, context: e })
}
},
});
Expand All @@ -247,17 +247,23 @@ export const registerListener = mutationField('registerPullResponderListener', {
filter: nonNull(InputListenerFilter),
},
resolve: async (_parent, { filter }, ctx: Context) => {
const result = await ctx.prisma.document.registerPullResponderListener(
ctx.driveId ?? '1',
{
try {
const result = await ctx.prisma.document.registerPullResponderListener(
ctx.driveId ?? '1',
{
branch: filter.branch?.filter(b => !!b) as string[] ?? [],
documentId: filter.documentId?.filter(b => !!b) as string[] ?? [],
documentType: filter.documentType?.filter(b => !!b) as string[] ?? [],
scope: filter.scope?.filter(b => !!b) as string[] ?? [],
},
);
},
);

return result;

} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to register listener", logging: true, context: e })
}

return result;
},
});

Expand All @@ -268,12 +274,16 @@ export const deleteListener = mutationField('deletePullResponderListener', {
filter: nonNull(InputListenerFilter),
},
resolve: async (_parent, { filter }, ctx: Context) => {
const result = await ctx.prisma.document.deletePullResponderListener(
ctx.driveId ?? '1',
filter,
);
try {
const result = await ctx.prisma.document.deletePullResponderListener(
ctx.driveId ?? '1',
filter,
);

return result;
return result;
} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to delete listener", logging: true, context: e })
}
},
});

Expand All @@ -286,36 +296,42 @@ export const pushUpdates = mutationField('pushUpdates', {
logger.info('pushUpdates')
if (!strands || strands?.length === 0) return [];

const listenerRevisions: IListenerRevision[] = await Promise.all(strands.map(async (s) => {
const operations = s.operations?.map((o) => ({
...o,
input: JSON.parse(o.input),
skip: o.skip ?? 0,
scope: s.scope as OperationScope,
branch: 'main',
scopes: ['global', 'local'],
})) ?? [];

const result = await ctx.prisma.document.pushUpdates(
s.driveId,
operations as Operation<DocumentDriveAction>[],
s.documentId ?? undefined,
);

if (result.status !== "SUCCESS") logger.error(result.error);

const revision = result.document?.operations[s.scope as OperationScope].slice().pop()?.index ?? -1;
return {
revision,
branch: s.branch,
documentId: s.documentId ?? '',
driveId: s.driveId,
scope: s.scope as OperationScope,
status: result.status,
};
}));

return listenerRevisions;
try {
const listenerRevisions: IListenerRevision[] = await Promise.all(strands.map(async (s) => {
const operations = s.operations?.map((o) => ({
...o,
input: JSON.parse(o.input),
skip: o.skip ?? 0,
scope: s.scope as OperationScope,
branch: 'main',
scopes: ['global', 'local'],
})) ?? [];

const result = await ctx.prisma.document.pushUpdates(
s.driveId,
operations as Operation<DocumentDriveAction>[],
s.documentId ?? undefined,
);

if (result.status !== "SUCCESS") logger.error(result.error);

const revision = result.document?.operations[s.scope as OperationScope].slice().pop()?.index ?? -1;
return {
revision,
branch: s.branch,
documentId: s.documentId ?? '',
driveId: s.driveId,
scope: s.scope as OperationScope,
status: result.status,
};

}));


return listenerRevisions;
} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to push updates", logging: true, context: e })
}
},
});

Expand Down Expand Up @@ -346,9 +362,8 @@ export const acknowledge = mutationField('acknowledge', {
);

return result;
} catch (e) {
logger.error(e)
return false;
} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to acknowledge", logging: true, context: e })
}
},
});
20 changes: 12 additions & 8 deletions api/src/modules/document-drive/drives-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { DocumentDriveState } from './drive-resolver';
import { Context } from '../../graphql/server/drive/context';
import logger from '../../logger';
import DocumentDriveError from '../../errors/DocumentDriveError';

export const DocumentDriveLocalState = objectType({
name: 'DocumentDriveLocalState',
Expand Down Expand Up @@ -68,11 +69,15 @@ export const addDrive = mutationField('addDrive', {
local: nonNull(DocumentDriveLocalStateInput),
},
resolve: async (_parent, { global, local }, ctx: Context) => {
const drive = await ctx.prisma.document.addDrive({
global: { id: global.id, name: global.name, icon: global.icon ?? null, slug: global.slug ?? null },
local: { availableOffline: local.availableOffline, sharingType: local.sharingType ?? null, listeners: [], triggers: [] },
});
return drive.state;
try {
const drive = await ctx.prisma.document.addDrive({
global: { id: global.id, name: global.name, icon: global.icon ?? null, slug: global.slug ?? null },
local: { availableOffline: local.availableOffline, sharingType: local.sharingType ?? null, listeners: [], triggers: [] },
});
return drive.state;
} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to add drive", logging: true, context: e })
}
},
});

Expand All @@ -84,9 +89,8 @@ export const deleteDrive = mutationField('deleteDrive', {
resolve: async (_parent, { id }, ctx: Context) => {
try {
await ctx.prisma.document.deleteDrive(id);
} catch (e) {
logger.error(e);
return false;
} catch (e: any) {
throw new DocumentDriveError({ code: 500, message: e.message ?? "Failed to delete drive", logging: true, context: e })
}

return true;
Expand Down
8 changes: 6 additions & 2 deletions api/src/modules/document/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ export function getDocumentDriveCRUD(prisma: Prisma.TransactionClient) {
);

async function initialize() {
await driveServer.initialize();
await init(driveServer, prisma);
try {
await driveServer.initialize();
await init(driveServer, prisma);
} catch (e) {
console.log(e);
}
}

function clearDriveCache() {
Expand Down

0 comments on commit b6fd264

Please sign in to comment.