diff --git a/CHANGELOG.md b/CHANGELOG.md index 639b90cc7..caa7ad63c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - The `serializer` property of `Documentation` and `Integration` constructor argument removed; - The `originalError` property of `InputValidationError` and `OutputValidationError` removed (use `cause` instead); - The `getStatusCodeFromError()` method removed (use the `ensureHttpError().statusCode` instead); +- Both `logger` and `getChildLogger` properties of `beforeRouting` argument are replaced with all-purpose `getLogger`: + - It returns the child logger for the given request (if configured) or the configured logger otherwise. - Specifying `method` or `methods` for `EndpointsFactory::build()` made optional and when it's omitted: - If the endpoint is assigned to a route using `DependsOnMethod` instance, the corresponding method is used; - Otherwise `GET` method is implied by default. diff --git a/README.md b/README.md index 3fe926366..e44e341cd 100644 --- a/README.md +++ b/README.md @@ -370,9 +370,13 @@ import { createConfig } from "express-zod-api"; import ui from "swagger-ui-express"; const config = createConfig({ - beforeRouting: ({ app, logger, getChildLogger }) => { + beforeRouting: ({ app, getLogger }) => { + const logger = getLogger(); logger.info("Serving the API documentation at https://example.com/docs"); app.use("/docs", ui.serve, ui.setup(documentation)); + app.use("/custom", (req, res, next) => { + const childLogger = getLogger(req); // if childLoggerProvider is configured + }); }, }); ``` diff --git a/src/config-type.ts b/src/config-type.ts index 620544877..519dad5f7 100644 --- a/src/config-type.ts +++ b/src/config-type.ts @@ -8,7 +8,7 @@ import { AbstractLogger, ActualLogger } from "./logger-helpers"; import { Method } from "./method"; import { AbstractResultHandler } from "./result-handler"; import { ListenOptions } from "node:net"; -import { ChildLoggerExtractor } from "./server-helpers"; +import { GetLogger } from "./server-helpers"; export type InputSource = keyof Pick< Request, @@ -131,13 +131,8 @@ interface GracefulOptions { type BeforeRouting = (params: { app: IRouter; - /** - * @desc Root logger, same for all requests - * @todo reconsider the naming in v21 - * */ - logger: ActualLogger; - /** @desc Returns a child logger if childLoggerProvider is configured (otherwise root logger) */ - getChildLogger: ChildLoggerExtractor; + /** @desc Returns child logger for the given request (if configured) or the configured logger otherwise */ + getLogger: GetLogger; }) => void | Promise; export interface HttpConfig { diff --git a/src/migration.ts b/src/migration.ts index e3ca50c06..72f013033 100644 --- a/src/migration.ts +++ b/src/migration.ts @@ -9,16 +9,21 @@ import { name as importName } from "../package.json"; const createConfigName = "createConfig"; const createServerName = "createServer"; const serverPropName = "server"; +const beforeRoutingPropName = "beforeRouting"; const httpServerPropName = "httpServer"; const httpsServerPropName = "httpsServer"; const originalErrorPropName = "originalError"; const getStatusCodeFromErrorMethod = "getStatusCodeFromError"; +const loggerPropName = "logger"; +const getChildLoggerPropName = "getChildLogger"; const changedProps = { [serverPropName]: "http", [httpServerPropName]: "servers", [httpsServerPropName]: "servers", [originalErrorPropName]: "cause", + [loggerPropName]: "getLogger", + [getChildLoggerPropName]: "getLogger", }; const changedMethods = { @@ -199,6 +204,41 @@ const v21 = ESLintUtils.RuleCreator.withoutDocs({ }); } }, + [`${NT.Property}[key.name="${beforeRoutingPropName}"] ${NT.ArrowFunctionExpression} ${NT.Identifier}[name="${loggerPropName}"]`]: + (node: TSESTree.Identifier) => { + const { parent } = node; + const isProp = isPropWithId(parent); + if (isProp && parent.value === node) return; // not for renames + const replacement = `${changedProps[node.name as keyof typeof changedProps]}${isProp ? "" : "()"}`; + ctx.report({ + node, + messageId: "change", + data: { + subject: isProp ? "property" : "const", + from: node.name, + to: replacement, + }, + fix: (fixer) => fixer.replaceText(node, replacement), + }); + }, + [`${NT.Property}[key.name="${beforeRoutingPropName}"] ${NT.ArrowFunctionExpression} ${NT.Identifier}[name="${getChildLoggerPropName}"]`]: + (node: TSESTree.Identifier) => { + const { parent } = node; + const isProp = isPropWithId(parent); + if (isProp && parent.value === node) return; // not for renames + const replacement = + changedProps[node.name as keyof typeof changedProps]; + ctx.report({ + node, + messageId: "change", + data: { + subject: isProp ? "property" : "method", + from: node.name, + to: replacement, + }, + fix: (fixer) => fixer.replaceText(node, replacement), + }); + }, }), }); diff --git a/src/routing.ts b/src/routing.ts index ee2e7c7c6..b141d3b03 100644 --- a/src/routing.ts +++ b/src/routing.ts @@ -4,11 +4,10 @@ import { ContentType, contentTypes } from "./content-type"; import { assertJsonCompatible } from "./deep-checks"; import { DependsOnMethod } from "./depends-on-method"; import { AbstractEndpoint } from "./endpoint"; -import { ActualLogger } from "./logger-helpers"; import { AuxMethod, Method } from "./method"; import { walkRouting } from "./routing-walker"; import { ServeStatic } from "./serve-static"; -import { ChildLoggerExtractor } from "./server-helpers"; +import { GetLogger } from "./server-helpers"; export interface Routing { [SEGMENT: string]: Routing | DependsOnMethod | AbstractEndpoint | ServeStatic; @@ -18,15 +17,13 @@ export type Parsers = Record; export const initRouting = ({ app, - rootLogger, - getChildLogger, + getLogger, config, routing, parsers, }: { app: IRouter; - rootLogger: ActualLogger; - getChildLogger: ChildLoggerExtractor; + getLogger: GetLogger; config: CommonConfig; routing: Routing; parsers?: Parsers; @@ -43,7 +40,7 @@ export const initRouting = ({ try { assertJsonCompatible(endpoint.getSchema("input"), "in"); } catch (reason) { - rootLogger.warn( + getLogger().warn( "The final input schema of the endpoint contains an unsupported JSON payload type.", { path, method, reason }, ); @@ -54,7 +51,7 @@ export const initRouting = ({ try { assertJsonCompatible(endpoint.getSchema(variant), "out"); } catch (reason) { - rootLogger.warn( + getLogger().warn( `The final ${variant} response schema of the endpoint contains an unsupported JSON payload type.`, { path, method, reason }, ); @@ -75,7 +72,7 @@ export const initRouting = ({ }; const matchingParsers = parsers?.[requestType] || []; const handler: RequestHandler = async (request, response) => { - const logger = getChildLogger(request); + const logger = getLogger(request); if (config.cors) { const headers = typeof config.cors === "function" diff --git a/src/server-helpers.ts b/src/server-helpers.ts index 57870f5c7..551f0b8fb 100644 --- a/src/server-helpers.ts +++ b/src/server-helpers.ts @@ -19,18 +19,16 @@ type EquippedRequest = Request< { [metaSymbol]?: { logger: ActualLogger } } >; -export type ChildLoggerExtractor = (request: Request) => ActualLogger; +/** @desc Returns child logger for the given request (if configured) or the configured logger otherwise */ +export type GetLogger = (request?: Request) => ActualLogger; interface HandlerCreatorParams { errorHandler: AbstractResultHandler; - getChildLogger: ChildLoggerExtractor; + getLogger: GetLogger; } export const createParserFailureHandler = - ({ - errorHandler, - getChildLogger, - }: HandlerCreatorParams): ErrorRequestHandler => + ({ errorHandler, getLogger }: HandlerCreatorParams): ErrorRequestHandler => async (error, request, response, next) => { if (!error) return next(); return errorHandler.execute({ @@ -42,18 +40,18 @@ export const createParserFailureHandler = input: null, output: null, options: {}, - logger: getChildLogger(request), + logger: getLogger(request), }); }; export const createNotFoundHandler = - ({ errorHandler, getChildLogger }: HandlerCreatorParams): RequestHandler => + ({ errorHandler, getLogger }: HandlerCreatorParams): RequestHandler => async (request, response) => { const error = createHttpError( 404, `Can not ${request.method} ${request.path}`, ); - const logger = getChildLogger(request); + const logger = getLogger(request); try { errorHandler.execute({ request, @@ -88,10 +86,10 @@ export const createUploadLogger = ( ): Pick => ({ log: logger.debug.bind(logger) }); export const createUploadParsers = async ({ - getChildLogger, + getLogger, config, }: { - getChildLogger: ChildLoggerExtractor; + getLogger: GetLogger; config: ServerConfig; }): Promise => { const uploader = await loadPeer("express-fileupload"); @@ -100,7 +98,7 @@ export const createUploadParsers = async ({ }; const parsers: RequestHandler[] = []; parsers.push(async (request, response, next) => { - const logger = getChildLogger(request); + const logger = getLogger(request); try { await beforeUpload?.({ request, logger }); } catch (error) { @@ -126,26 +124,26 @@ export const moveRaw: RequestHandler = (req, {}, next) => { /** @since v19 prints the actual path of the request, not a configured route, severity decreased to debug level */ export const createLoggingMiddleware = ({ - rootLogger, + logger: parent, config, }: { - rootLogger: ActualLogger; + logger: ActualLogger; config: CommonConfig; }): RequestHandler => async (request, response, next) => { - const logger = config.childLoggerProvider - ? await config.childLoggerProvider({ request, parent: rootLogger }) - : rootLogger; + const logger = + (await config.childLoggerProvider?.({ request, parent })) || parent; logger.debug(`${request.method}: ${request.path}`); if (request.res) (request as EquippedRequest).res!.locals[metaSymbol] = { logger }; next(); }; -export const makeChildLoggerExtractor = - (fallback: ActualLogger): ChildLoggerExtractor => +export const makeGetLogger = + (fallback: ActualLogger): GetLogger => (request) => - (request as EquippedRequest).res?.locals[metaSymbol]?.logger || fallback; + (request as EquippedRequest | undefined)?.res?.locals[metaSymbol]?.logger || + fallback; export const installDeprecationListener = (logger: ActualLogger) => process.on("deprecation", ({ message, namespace, name, stack }) => diff --git a/src/server.ts b/src/server.ts index d647165dd..b1bc86d51 100644 --- a/src/server.ts +++ b/src/server.ts @@ -18,7 +18,7 @@ import { createNotFoundHandler, createParserFailureHandler, createUploadParsers, - makeChildLoggerExtractor, + makeGetLogger, installDeprecationListener, moveRaw, installTerminationListener, @@ -28,22 +28,22 @@ import { getStartupLogo } from "./startup-logo"; const makeCommonEntities = (config: CommonConfig) => { if (config.startupLogo !== false) console.log(getStartupLogo()); const errorHandler = config.errorHandler || defaultResultHandler; - const rootLogger = isLoggerInstance(config.logger) + const logger = isLoggerInstance(config.logger) ? config.logger : new BuiltinLogger(config.logger); - rootLogger.debug("Running", { + logger.debug("Running", { build: process.env.TSUP_BUILD || "from sources", env: process.env.NODE_ENV || "development", }); - installDeprecationListener(rootLogger); - const loggingMiddleware = createLoggingMiddleware({ rootLogger, config }); - const getChildLogger = makeChildLoggerExtractor(rootLogger); - const commons = { getChildLogger, errorHandler }; + installDeprecationListener(logger); + const loggingMiddleware = createLoggingMiddleware({ logger, config }); + const getLogger = makeGetLogger(logger); + const commons = { getLogger, errorHandler }; const notFoundHandler = createNotFoundHandler(commons); const parserFailureHandler = createParserFailureHandler(commons); return { ...commons, - rootLogger, + logger, notFoundHandler, parserFailureHandler, loggingMiddleware, @@ -51,22 +51,21 @@ const makeCommonEntities = (config: CommonConfig) => { }; export const attachRouting = (config: AppConfig, routing: Routing) => { - const { rootLogger, getChildLogger, notFoundHandler, loggingMiddleware } = + const { logger, getLogger, notFoundHandler, loggingMiddleware } = makeCommonEntities(config); initRouting({ app: config.app.use(loggingMiddleware), - rootLogger, routing, - getChildLogger, + getLogger, config, }); - return { notFoundHandler, logger: rootLogger }; + return { notFoundHandler, logger }; }; export const createServer = async (config: ServerConfig, routing: Routing) => { const { - rootLogger, - getChildLogger, + logger, + getLogger, notFoundHandler, parserFailureHandler, loggingMiddleware, @@ -86,23 +85,17 @@ export const createServer = async (config: ServerConfig, routing: Routing) => { json: [config.jsonParser || express.json()], raw: [config.rawParser || express.raw(), moveRaw], upload: config.upload - ? await createUploadParsers({ config, getChildLogger }) + ? await createUploadParsers({ config, getLogger }) : [], }; - if (config.beforeRouting) { - await config.beforeRouting({ - app, - logger: rootLogger, - getChildLogger, - }); - } - initRouting({ app, routing, rootLogger, getChildLogger, config, parsers }); + await config.beforeRouting?.({ app, getLogger }); + initRouting({ app, routing, getLogger, config, parsers }); app.use(parserFailureHandler, notFoundHandler); const makeStarter = (server: http.Server | https.Server, subject: HttpConfig["listen"]) => () => - server.listen(subject, () => rootLogger.info("Listening", subject)); + server.listen(subject, () => logger.info("Listening", subject)); const created: Array = []; const starters: Array<() => http.Server | https.Server> = []; @@ -119,15 +112,11 @@ export const createServer = async (config: ServerConfig, routing: Routing) => { if (config.gracefulShutdown) { installTerminationListener({ + logger, servers: created, - logger: rootLogger, options: config.gracefulShutdown === true ? {} : config.gracefulShutdown, }); } - return { - app, - logger: rootLogger, - servers: starters.map((starter) => starter()), - }; + return { app, logger, servers: starters.map((starter) => starter()) }; }; diff --git a/tests/system/system.spec.ts b/tests/system/system.spec.ts index 108c84155..a866dac0a 100644 --- a/tests/system/system.spec.ts +++ b/tests/system/system.spec.ts @@ -112,10 +112,10 @@ describe("App in production mode", async () => { const config = createConfig({ http: { listen: port }, compression: { threshold: 1 }, - beforeRouting: ({ app, getChildLogger }) => { + beforeRouting: ({ app, getLogger }) => { depd("express")("Sample deprecation message"); app.use((req, {}, next) => { - const childLogger = getChildLogger(req); + const childLogger = getLogger(req); assert("isChild" in childLogger && childLogger.isChild); next(); }); diff --git a/tests/unit/migration.spec.ts b/tests/unit/migration.spec.ts index c041c7801..c68c983ad 100644 --- a/tests/unit/migration.spec.ts +++ b/tests/unit/migration.spec.ts @@ -22,6 +22,7 @@ describe("Migration", () => { `(() => {})()`, `createConfig({ http: {} });`, `createConfig({ http: { listen: 8090 }, upload: true });`, + `createConfig({ beforeRouting: ({ getLogger }) => { getLogger().warn() } });`, `const { app, servers, logger } = await createServer();`, `console.error(error.cause?.message);`, `import { ensureHttpError } from "express-zod-api";`, @@ -52,6 +53,50 @@ describe("Migration", () => { }, ], }, + { + code: `createConfig({ beforeRouting: ({ logger }) => { logger.warn() } });`, + output: `createConfig({ beforeRouting: ({ getLogger }) => { getLogger().warn() } });`, + errors: [ + { + messageId: "change", + data: { + subject: "property", + from: "logger", + to: "getLogger", + }, + }, + { + messageId: "change", + data: { + subject: "const", + from: "logger", + to: "getLogger()", + }, + }, + ], + }, + { + code: `createConfig({ beforeRouting: ({ getChildLogger }) => { getChildLogger(request).warn() } });`, + output: `createConfig({ beforeRouting: ({ getLogger }) => { getLogger(request).warn() } });`, + errors: [ + { + messageId: "change", + data: { + subject: "property", + from: "getChildLogger", + to: "getLogger", + }, + }, + { + messageId: "change", + data: { + subject: "method", + from: "getChildLogger", + to: "getLogger", + }, + }, + ], + }, { code: `const { app, httpServer, httpsServer, logger } = await createServer();`, errors: [ diff --git a/tests/unit/routing.spec.ts b/tests/unit/routing.spec.ts index 4d9eda3de..b85f440af 100644 --- a/tests/unit/routing.spec.ts +++ b/tests/unit/routing.spec.ts @@ -6,7 +6,6 @@ import { } from "../express-mock"; import { z } from "zod"; import { - BuiltinLogger, DependsOnMethod, CommonConfig, EndpointsFactory, @@ -64,13 +63,12 @@ describe("Routing", () => { }, }, }; - const rootLogger = new BuiltinLogger({ level: "silent" }); + const logger = makeLoggerMock(); initRouting({ app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing, - rootLogger, }); expect(appMock.get).toHaveBeenCalledTimes(2); expect(appMock.post).toHaveBeenCalledTimes(2); @@ -95,13 +93,12 @@ describe("Routing", () => { cors: true, startupLogo: false, }; - const rootLogger = new BuiltinLogger({ level: "silent" }); + const logger = makeLoggerMock(); initRouting({ app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing, - rootLogger, }); expect(staticMock).toHaveBeenCalledWith(__dirname, { dotfiles: "deny" }); expect(appMock.use).toHaveBeenCalledTimes(1); @@ -137,13 +134,12 @@ describe("Routing", () => { }), }, }; - const rootLogger = new BuiltinLogger({ level: "silent" }); + const logger = makeLoggerMock(); initRouting({ app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing, - rootLogger, }); expect(appMock.get).toHaveBeenCalledTimes(1); expect(appMock.post).toHaveBeenCalledTimes(1); @@ -175,14 +171,13 @@ describe("Routing", () => { }), }, }; - const rootLogger = new BuiltinLogger({ level: "silent" }); + const logger = makeLoggerMock(); expect(() => initRouting({ app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing, - rootLogger, }), ).toThrowErrorMatchingSnapshot(); }); @@ -222,13 +217,12 @@ describe("Routing", () => { patch: putAndPatchEndpoint, }), }; - const rootLogger = new BuiltinLogger({ level: "silent" }); + const logger = makeLoggerMock(); initRouting({ app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing, - rootLogger, }); expect(appMock.options).toHaveBeenCalledTimes(1); expect(appMock.options.mock.calls[0][0]).toBe("/hello"); @@ -262,13 +256,12 @@ describe("Routing", () => { }, }, }; - const rootLogger = new BuiltinLogger({ level: "silent" }); + const logger = makeLoggerMock(); initRouting({ app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing, - rootLogger, }); expect(appMock.get).toHaveBeenCalledTimes(1); expect(appMock.get.mock.calls[0][0]).toBe("/v1/user/:id"); @@ -292,13 +285,12 @@ describe("Routing", () => { }, }, }; - const rootLogger = new BuiltinLogger({ level: "silent" }); + const logger = makeLoggerMock(); initRouting({ app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing, - rootLogger, }); expect(appMock.get).toHaveBeenCalledTimes(2); expect(appMock.get.mock.calls[0][0]).toBe("/v1/user/:id"); @@ -313,12 +305,11 @@ describe("Routing", () => { output: z.object({}), handler: handlerMock, }); - const rootLogger = new BuiltinLogger({ level: "silent" }); + const logger = makeLoggerMock(); expect(() => initRouting({ - rootLogger, app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing: { v1: { @@ -329,9 +320,8 @@ describe("Routing", () => { ).toThrowErrorMatchingSnapshot(); expect(() => initRouting({ - rootLogger, app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing: { "v1/user/retrieve": endpointMock, @@ -362,12 +352,10 @@ describe("Routing", () => { }, }, }; - const rootLogger = makeLoggerMock(); - const childLogger = makeLoggerMock(); + const getLoggerMock = vi.fn(() => makeLoggerMock()); initRouting({ - rootLogger, app: appMock as unknown as IRouter, - getChildLogger: () => childLogger, + getLogger: getLoggerMock, config: configMock as CommonConfig, routing, }); @@ -380,15 +368,16 @@ describe("Routing", () => { const responseMock = makeResponseMock(); const nextMock = vi.fn(); await routeHandler(requestMock, responseMock, nextMock); + expect(getLoggerMock).toHaveBeenCalledWith(requestMock); expect(nextMock).toHaveBeenCalledTimes(0); expect(handlerMock).toHaveBeenCalledTimes(1); - expect(childLogger._getLogs().error).toHaveLength(0); + expect( + getLoggerMock.mock.results.pop()!.value._getLogs().error, + ).toHaveLength(0); expect(handlerMock).toHaveBeenCalledWith({ - input: { - test: 123, - }, + input: { test: 123 }, options: {}, - logger: childLogger, + logger: getLoggerMock.mock.results.pop()!.value, }); expect(responseMock._getStatusCode()).toBe(200); expect(responseMock._getJSONData()).toEqual({ @@ -413,15 +402,14 @@ describe("Routing", () => { handler: vi.fn(), }); const configMock = { cors: false, startupLogo: false }; - const rootLogger = makeLoggerMock(); + const logger = makeLoggerMock(); initRouting({ - rootLogger, app: appMock as unknown as IRouter, - getChildLogger: () => rootLogger, + getLogger: () => logger, config: configMock as CommonConfig, routing: { path: endpoint }, }); - expect(rootLogger._getLogs().warn).toEqual([ + expect(logger._getLogs().warn).toEqual([ [ "The final input schema of the endpoint contains an unsupported JSON payload type.", { method: "get", path: "/path", reason: expect.any(Error) }, diff --git a/tests/unit/server-helpers.spec.ts b/tests/unit/server-helpers.spec.ts index af570746b..6e835558e 100644 --- a/tests/unit/server-helpers.spec.ts +++ b/tests/unit/server-helpers.spec.ts @@ -7,7 +7,7 @@ import { createUploadFailureHandler, createUploadLogger, createUploadParsers, - makeChildLoggerExtractor, + makeGetLogger, moveRaw, installDeprecationListener, installTerminationListener, @@ -26,7 +26,7 @@ describe("Server helpers", () => { test("the handler should call next if there is no error", () => { const handler = createParserFailureHandler({ errorHandler: defaultResultHandler, - getChildLogger: () => makeLoggerMock(), + getLogger: () => makeLoggerMock(), }); const next = vi.fn(); handler(undefined, makeRequestMock(), makeResponseMock(), next); @@ -47,7 +47,7 @@ describe("Server helpers", () => { const spy = vi.spyOn(errorHandler, "execute"); const handler = createParserFailureHandler({ errorHandler, - getChildLogger: () => makeLoggerMock(), + getLogger: () => makeLoggerMock(), }); await handler( error, @@ -73,7 +73,7 @@ describe("Server helpers", () => { const spy = vi.spyOn(errorHandler, "execute"); const handler = createNotFoundHandler({ errorHandler, - getChildLogger: () => makeLoggerMock(), + getLogger: () => makeLoggerMock(), }); const next = vi.fn(); const requestMock = makeRequestMock({ @@ -104,7 +104,7 @@ describe("Server helpers", () => { const spy = vi.spyOn(errorHandler, "execute"); const handler = createNotFoundHandler({ errorHandler, - getChildLogger: () => makeLoggerMock(), + getLogger: () => makeLoggerMock(), }); const next = vi.fn(); const requestMock = makeRequestMock({ @@ -151,12 +151,12 @@ describe("Server helpers", () => { }); describe("createUploadLogger()", () => { - const rootLogger = makeLoggerMock(); - const uploadLogger = createUploadLogger(rootLogger); + const logger = makeLoggerMock(); + const uploadLogger = createUploadLogger(logger); test("should debug the messages", () => { uploadLogger.log("Express-file-upload: Busboy finished parsing request."); - expect(rootLogger._getLogs().debug).toEqual([ + expect(logger._getLogs().debug).toEqual([ ["Express-file-upload: Busboy finished parsing request."], ]); }); @@ -176,7 +176,7 @@ describe("Server helpers", () => { cors: false, logger: { level: "silent" }, }, - getChildLogger: () => loggerMock, + getLogger: () => loggerMock, }); const requestMock = makeRequestMock(); const responseMock = makeResponseMock(); @@ -237,13 +237,13 @@ describe("Server helpers", () => { }); describe("createLoggingMiddleware", () => { - const rootLogger = makeLoggerMock(); + const logger = makeLoggerMock(); const child = makeLoggerMock({ isChild: true }); test.each([undefined, () => child, async () => child])( "should make RequestHandler writing logger to res.locals %#", async (childLoggerProvider) => { const config = { childLoggerProvider } as CommonConfig; - const handler = createLoggingMiddleware({ rootLogger, config }); + const handler = createLoggingMiddleware({ logger, config }); expect(typeof handler).toBe("function"); const nextMock = vi.fn(); const response = makeResponseMock(); @@ -252,18 +252,18 @@ describe("Server helpers", () => { await handler(request, response, nextMock); expect(nextMock).toHaveBeenCalled(); expect( - (childLoggerProvider ? child : rootLogger)._getLogs().debug.pop(), + (childLoggerProvider ? child : logger)._getLogs().debug.pop(), ).toEqual(["GET: /test"]); expect(request.res).toHaveProperty("locals", { - [metaSymbol]: { logger: childLoggerProvider ? child : rootLogger }, + [metaSymbol]: { logger: childLoggerProvider ? child : logger }, }); }, ); }); - describe("makeChildLoggerExtractor()", () => { - const rootLogger = makeLoggerMock(); - const getChildLogger = makeChildLoggerExtractor(rootLogger); + describe("makeGetLogger()", () => { + const logger = makeLoggerMock(); + const getLogger = makeGetLogger(logger); test("should extract child logger from request", () => { const request = makeRequestMock({ @@ -273,13 +273,15 @@ describe("Server helpers", () => { }, }, }); - expect(getChildLogger(request)).toHaveProperty("isChild", true); + expect(getLogger(request)).toHaveProperty("isChild", true); }); - test("should fall back to root", () => { - const request = makeRequestMock(); - expect(getChildLogger(request)).toEqual(rootLogger); - }); + test.each([makeRequestMock(), undefined])( + "should fall back to root %#", + (request) => { + expect(getLogger(request)).toEqual(logger); + }, + ); }); describe("installDeprecationListener()", () => { diff --git a/tests/unit/server.spec.ts b/tests/unit/server.spec.ts index 3b91acc65..447fbdeaa 100644 --- a/tests/unit/server.spec.ts +++ b/tests/unit/server.spec.ts @@ -141,8 +141,7 @@ describe("Server", () => { expect(configMock.errorHandler.handler).toHaveBeenCalledTimes(0); expect(configMock.beforeRouting).toHaveBeenCalledWith({ app: appMock, - logger: customLogger, - getChildLogger: expect.any(Function), + getLogger: expect.any(Function), }); expect(infoMethod).toHaveBeenCalledTimes(1); expect(infoMethod).toHaveBeenCalledWith(`Listening`, { port });