Skip to content

Commit

Permalink
Capture server errors in NestJS (#53)
Browse files Browse the repository at this point in the history
* Add test

* Add NestJS exceptions filter
  • Loading branch information
itssimon authored Nov 5, 2024
1 parent 7267e75 commit 0c49f78
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 8 deletions.
24 changes: 23 additions & 1 deletion src/nestjs/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,24 @@
import { ArgumentsHost, Catch, INestApplication } from "@nestjs/common";
import { BaseExceptionFilter } from "@nestjs/core";
import { Response } from "express";

import type { ApitallyConfig } from "../common/types.js";
import { useApitally as useApitallyExpress } from "../express/index.js";
export type { ApitallyConsumer } from "../common/types.js";
export { useApitally } from "../express/index.js";

export const useApitally = (app: INestApplication, config: ApitallyConfig) => {
const httpAdapter = app.getHttpAdapter();
const expressInstance = httpAdapter.getInstance();
useApitallyExpress(expressInstance, config);
app.useGlobalFilters(new AllExceptionsFilter(httpAdapter));
};

@Catch()
class AllExceptionsFilter extends BaseExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const res = ctx.getResponse<Response>();
res.locals.serverError = exception;
super.catch(exception, host);
}
}
3 changes: 2 additions & 1 deletion tests/express/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ testCases.forEach(({ name, getApp }) => {
await appTest.get("/error").expect(500);

const requests = client.requestCounter.getAndResetRequests();
const serverErrors = client.serverErrorCounter.getAndResetServerErrors();
expect(requests.length).toBe(4);
expect(
requests.some(
Expand Down Expand Up @@ -76,6 +75,8 @@ testCases.forEach(({ name, getApp }) => {
expect(
requests.some((r) => r.status_code === 500 && r.request_count === 1),
).toBe(true);

const serverErrors = client.serverErrorCounter.getAndResetServerErrors();
expect(serverErrors.length).toBe(1);
expect(
serverErrors.some(
Expand Down
3 changes: 2 additions & 1 deletion tests/fastify/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ describe("Plugin for Fastify", () => {
await appTest.get("/error").expect(500);

const requests = client.requestCounter.getAndResetRequests();
const serverErrors = client.serverErrorCounter.getAndResetServerErrors();
expect(requests.length).toBe(4);
expect(
requests.some(
Expand Down Expand Up @@ -60,6 +59,8 @@ describe("Plugin for Fastify", () => {
expect(
requests.some((r) => r.status_code === 500 && r.request_count === 1),
).toBe(true);

const serverErrors = client.serverErrorCounter.getAndResetServerErrors();
expect(serverErrors.length).toBe(1);
expect(
serverErrors.some(
Expand Down
3 changes: 2 additions & 1 deletion tests/hono/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ describe("Middleware for Hono", () => {
expect(res.status).toBe(500);

const requests = client.requestCounter.getAndResetRequests();
const serverErrors = client.serverErrorCounter.getAndResetServerErrors();
expect(requests.length).toBe(5);
expect(
requests.some(
Expand Down Expand Up @@ -89,6 +88,8 @@ describe("Middleware for Hono", () => {
expect(
requests.some((r) => r.status_code === 500 && r.request_count === 1),
).toBe(true);

const serverErrors = client.serverErrorCounter.getAndResetServerErrors();
expect(serverErrors.length).toBe(1);
expect(
serverErrors.some(
Expand Down
3 changes: 2 additions & 1 deletion tests/koa/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ testCases.forEach(({ name, router, getApp }) => {
consoleSpy.mockRestore();

const requests = client.requestCounter.getAndResetRequests();
const serverErrors = client.serverErrorCounter.getAndResetServerErrors();
expect(requests.length).toBe(3);
expect(
requests.some(
Expand All @@ -73,6 +72,8 @@ testCases.forEach(({ name, router, getApp }) => {
),
).toBe(true);
expect(requests.some((r) => r.status_code === 500)).toBe(true);

const serverErrors = client.serverErrorCounter.getAndResetServerErrors();
expect(serverErrors.length).toBe(1);
expect(
serverErrors.some(
Expand Down
2 changes: 1 addition & 1 deletion tests/nestjs/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ export class AppController {

@Get("/error")
getError() {
throw new Error("Error");
throw new Error("test");
}
}
12 changes: 12 additions & 0 deletions tests/nestjs/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ describe("Middleware for NestJS", () => {
expect(
requests.some((r) => r.status_code === 500 && r.request_count === 1),
).toBe(true);

const serverErrors = client.serverErrorCounter.getAndResetServerErrors();
expect(serverErrors.length).toBe(1);
expect(
serverErrors.some(
(e) =>
e.type === "Error" &&
e.msg === "test" &&
e.traceback &&
e.error_count === 1,
),
).toBe(true);
});

it("Validation error logger", async () => {
Expand Down
3 changes: 1 addition & 2 deletions tests/nestjs/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ export async function getApp() {
providers: [],
}).compile();
const app = moduleFixture.createNestApplication();
const expressInstance = app.getHttpAdapter().getInstance();

useApitally(expressInstance, {
useApitally(app, {
clientId: CLIENT_ID,
env: ENV,
appVersion: "1.2.3",
Expand Down

0 comments on commit 0c49f78

Please sign in to comment.