Skip to content

Commit

Permalink
feat: allow capturing logs
Browse files Browse the repository at this point in the history
  • Loading branch information
svedova committed Apr 19, 2024
1 parent dd6e79c commit 3a1b55d
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 6 deletions.
13 changes: 8 additions & 5 deletions src/request.ts
@@ -1,6 +1,7 @@
import { Socket } from "node:net";
import http from "node:http";
import { Readable } from "node:stream";
import { Logger } from "./utils/logger";

export interface RequestEvent {
url: string; // /relative/path?query=value#hash
Expand All @@ -10,14 +11,12 @@ export interface RequestEvent {
headers: http.IncomingHttpHeaders;
remoteAddress?: string;
remotePort?: string;
context?: {
features?: Record<string, boolean>;
apiKey?: string;
envId?: string;
};
captureLogs?: boolean;
}

class Request extends http.IncomingMessage {
logger?: Logger;

constructor(props: RequestEvent) {
const socket = {
readable: false,
Expand All @@ -31,6 +30,10 @@ class Request extends http.IncomingMessage {

super(socket);

if (props.captureLogs) {
this.logger = new Logger();
}

// Node.js < 13 support
this.connection = socket;

Expand Down
2 changes: 2 additions & 0 deletions src/response.ts
Expand Up @@ -10,6 +10,7 @@ export interface ServerlessResponse {
status?: number;
statusMessage?: string;
headers?: Record<string, string | string[]>;
logs?: string;
}

class Response extends ServerResponse {
Expand Down Expand Up @@ -42,6 +43,7 @@ class Response extends ServerResponse {
headers: parsed.headers,
statusMessage: parsed.statusMessage || "OK",
status: parsed.statusCode || 200,
logs: req.logger?.logs(),
});
});
}
Expand Down
16 changes: 16 additions & 0 deletions src/utils/callbacks/api.spec.ts
Expand Up @@ -12,12 +12,20 @@ jest.mock("~/utils/filesys", () => ({

describe("utils/callback/api.ts", () => {
describe("handleApi", () => {
const expectedLogs =
"this is an info\n" +
"this info log should be captured\n" +
"this is another info\n" +
"this error log should be captured\n" +
"this comes from process.stdout.write";

const exampleRequest = {
method: "GET",
url: "/",
path: "/",
body: "",
headers: {},
captureLogs: true,
};

afterEach(() => {
Expand All @@ -30,6 +38,12 @@ describe("utils/callback/api.ts", () => {
"/path/to/api-file.ts",
() => ({
default: () => {
console.info("this is an info");
console.log("this info log should be captured");
console.info("this is another info");
console.error("this error log should be captured");
process.stdout.write("this comes from process.stdout.write");

return {
body: "Hello world",
status: 201,
Expand All @@ -49,6 +63,7 @@ describe("utils/callback/api.ts", () => {
expect(response).toEqual({
body: "Hello world",
status: 201,
logs: expectedLogs,
headers: {
"X-Custom-Header": "Sample Project",
},
Expand Down Expand Up @@ -78,6 +93,7 @@ describe("utils/callback/api.ts", () => {
buffer: "SGkgd29ybGQ=",
status: 200,
statusMessage: "OK",
logs: expectedLogs,
headers: {
connection: "close",
date: expect.any(String),
Expand Down
2 changes: 1 addition & 1 deletion src/utils/callbacks/api.ts
Expand Up @@ -70,7 +70,7 @@ export const handleApi = (
const ret = await invokeApiHandler(mod, req, res);

if (ret) {
resolve(ret);
resolve({ ...ret, logs: req.logger?.logs() });
}

return;
Expand Down
38 changes: 38 additions & 0 deletions src/utils/logger.ts
@@ -0,0 +1,38 @@
import stream from "node:stream";

const stdout: string[] = [];
const originalConsole = console;
const originalStdout = process.stdout.write;
const originalStderr = process.stderr.write;

class Stdout extends stream.Writable {
_write(
chunk: any,
_: BufferEncoding,
callback: (error?: Error | null) => void
): void {
stdout.push(chunk.toString());
callback(null);
}
}

export class Logger {
constructor() {
const stream = new Stdout();

// @ts-ignore;
process.stdout.write = process.stderr.write = stream.write.bind(stream);
console = new console.Console(new Stdout(), new Stdout());
}

logs(): string {
this.restore();
return stdout.join("");
}

restore() {
console = originalConsole;
process.stdout.write = originalStdout;
process.stderr.write = originalStderr;
}
}

0 comments on commit 3a1b55d

Please sign in to comment.