diff --git a/src/response.ts b/src/response.ts index 48b8c4b..474f0d7 100644 --- a/src/response.ts +++ b/src/response.ts @@ -1,3 +1,4 @@ +import type { Log } from "./utils/logger"; import { Socket } from "node:net"; import { ServerResponse } from "node:http"; import httpParse from "./http-parser"; @@ -10,7 +11,7 @@ export interface ServerlessResponse { status?: number; statusMessage?: string; headers?: Record; - logs?: string; + logs?: Log[]; } class Response extends ServerResponse { diff --git a/src/utils/callbacks/api.spec.ts b/src/utils/callbacks/api.spec.ts index 1cf6a80..b1b7095 100644 --- a/src/utils/callbacks/api.spec.ts +++ b/src/utils/callbacks/api.spec.ts @@ -10,7 +10,18 @@ jest.mock("~/utils/filesys", () => ({ }, })); +const originalDateNow = Date.now; +const ts = 1487076708000; + describe("utils/callback/api.ts", () => { + beforeEach(() => { + Date.now = jest.fn(() => ts); //14.02.2017 + }); + + afterEach(() => { + Date.now = originalDateNow; + }); + describe("handleApi", () => { const exampleRequest = { method: "GET", @@ -53,17 +64,16 @@ describe("utils/callback/api.ts", () => { test("should handle returning a response body", async () => { const response = await handleApi(exampleRequest, "/"); - const expectedLogs = - "stdout:this is an info\n" + - "stdout:this info log should be captured\n" + - "stdout:this is another info\n" + - "stderr:this error log should be captured\n" + - "stdout:this comes from process.stdout.write"; - expect(response).toEqual({ body: "Hello world", status: 201, - logs: expectedLogs, + logs: [ + { ts, msg: "this is an info\n", level: "info" }, + { ts, msg: "this info log should be captured\n", level: "info" }, + { ts, msg: "this is another info\n", level: "info" }, + { ts, msg: "this error log should be captured\n", level: "error" }, + { ts, msg: "this comes from process.stdout.write", level: "info" }, + ], headers: { "X-Custom-Header": "Sample Project", }, @@ -94,7 +104,7 @@ describe("utils/callback/api.ts", () => { buffer: "SGkgd29ybGQ=", status: 200, statusMessage: "OK", - logs: "stdout:captured logs\n", + logs: [{ ts, msg: "captured logs\n", level: "info" }], headers: { connection: "close", date: expect.any(String), diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 3b0ec95..364d341 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -4,12 +4,18 @@ const originalConsole = console; const originalStdout = process.stdout.write; const originalStderr = process.stderr.write; +export interface Log { + level: "info" | "error"; + msg: string; + ts: number; +} + export class Logger { - stdout: string[] = []; + stdout: Log[] = []; constructor() { - const stdout = this.streamWithContext("stdout"); - const stderr = this.streamWithContext("stderr"); + const stdout = this.streamWithContext("info"); + const stderr = this.streamWithContext("error"); // @ts-ignore process.stdout.write = stdout.write.bind(stdout); @@ -17,27 +23,32 @@ export class Logger { process.stderr.write = stderr.write.bind(stdout); console = new console.Console( - this.streamWithContext("stdout"), - this.streamWithContext("stderr") + this.streamWithContext("info"), + this.streamWithContext("error") ); } - streamWithContext(level: "stderr" | "stdout") { + streamWithContext(level: "info" | "error") { return new stream.Writable({ write: ( chunk: any, _: BufferEncoding, callback: (error?: Error | null) => void ): void => { - this.stdout.push(`${level}:${chunk.toString()}`); + this.stdout.push({ + ts: Date.now(), + msg: chunk.toString(), + level, + }); + callback(null); }, }); } - logs(): string { + logs(): Log[] { this.restore(); - return this.stdout.join(""); + return this.stdout; } restore() {