diff --git a/src/index.ts b/src/index.ts index 8ede717..29d949f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,8 +15,9 @@ export function requestLog(octokit: Octokit) { return (request as typeof octokit.request)(options) .then((response) => { + const requestId = response.headers["x-github-request-id"]; octokit.log.info( - `${requestOptions.method} ${path} - ${response.status} in ${ + `${requestOptions.method} ${path} - ${response.status} with id ${requestId} in ${ Date.now() - start }ms`, ); @@ -24,8 +25,10 @@ export function requestLog(octokit: Octokit) { }) .catch((error) => { - octokit.log.info( - `${requestOptions.method} ${path} - ${error.status} in ${ + const requestId = + error.response.headers["x-github-request-id"] || "UNKNOWN"; + octokit.log.error( + `${requestOptions.method} ${path} - ${error.status} with id ${requestId} in ${ Date.now() - start }ms`, ); diff --git a/test/request-log.test.ts b/test/request-log.test.ts index 8cdc958..581a853 100644 --- a/test/request-log.test.ts +++ b/test/request-log.test.ts @@ -5,10 +5,16 @@ import { jest } from "@jest/globals"; import { requestLog } from "../src/index.js"; describe("logging", () => { - it("logs sucessful 'GET /'", async () => { - const mock = fetchMock - .sandbox() - .getOnce("https://api.github.com/", { ok: true }); + it("logs successful 'GET /'", async () => { + const mock = fetchMock.sandbox().getOnce("https://api.github.com/", { + status: 200, + body: { + ok: true, + }, + headers: { + "x-github-request-id": "1234", + }, + }); const mockLogInfo = jest.fn(); const mockDebugInfo = jest.fn(); @@ -31,15 +37,22 @@ describe("logging", () => { method: "GET", url: "/", }); - expect(mockLogInfo.mock.calls[0][0]).toMatch(/GET \/ - 200 in \d+ms/); + expect(mockLogInfo.mock.calls[0][0]).toMatch( + /GET \/ - 200 with id 1234 in \d+ms/, + ); }); it("logs 404 for 'GET /unknown'", async () => { - const mock = fetchMock - .sandbox() - .getOnce("https://api.github.com/unknown", 404); + const mock = fetchMock.sandbox().getOnce("https://api.github.com/unknown", { + status: 404, + body: { message: "Not Found" }, + headers: { + "x-github-request-id": "1234", + }, + }); const mockLogInfo = jest.fn(); + const mockErrorInfo = jest.fn(); const mockDebugInfo = jest.fn(); const MyOctokit = Octokit.plugin(requestLog); const octokit = new MyOctokit({ @@ -50,15 +63,49 @@ describe("logging", () => { debug: mockDebugInfo, info: mockLogInfo, warn() {}, - error() {}, + error: mockErrorInfo, + }, + }); + + try { + await octokit.request("GET /unknown"); + } catch (error) { + expect(mockErrorInfo.mock.calls[0][0]).toMatch( + /GET \/unknown - 404 with id 1234 in \d+ms/, + ); + return; + } + + throw new Error('"GET /unknown" should not resolve'); + }); + + it("logs malformed error response for 'GET /unknown'", async () => { + const mock = fetchMock.sandbox().getOnce("https://api.github.com/unknown", { + status: 500, + body: "Internal Server Error", + }); + + const mockLogInfo = jest.fn(); + const mockErrorInfo = jest.fn(); + const mockDebugInfo = jest.fn(); + const MyOctokit = Octokit.plugin(requestLog); + const octokit = new MyOctokit({ + request: { + fetch: mock, + }, + log: { + debug: mockDebugInfo, + info: mockLogInfo, + warn() {}, + error: mockErrorInfo, }, }); try { await octokit.request("GET /unknown"); } catch (error) { - expect(mockLogInfo.mock.calls[0][0]).toMatch( - /GET \/unknown - 404 in \d+ms/, + expect(mockErrorInfo.mock.calls[0][0]).toMatch( + /GET \/unknown - 500 with id UNKNOWN in \d+ms/, ); return; }