| |
| import { beforeEach, describe, expect, it, vi } from "vitest"; |
|
|
| const loggingMocks = vi.hoisted(() => { |
| const childLogger = { |
| debug: vi.fn(), |
| info: vi.fn(), |
| warn: vi.fn(), |
| error: vi.fn(), |
| }; |
| const isFileLogLevelEnabled = vi.fn((_level: string) => true); |
| return { |
| childLogger, |
| getChildLogger: vi.fn(() => childLogger), |
| isFileLogLevelEnabled, |
| }; |
| }); |
|
|
| vi.mock("../../globals.js", () => ({ |
| shouldLogVerbose: vi.fn(() => false), |
| })); |
|
|
| vi.mock("../../logging.js", () => ({ |
| getChildLogger: loggingMocks.getChildLogger, |
| isFileLogLevelEnabled: loggingMocks.isFileLogLevelEnabled, |
| })); |
|
|
| let createRuntimeLogging: typeof import("./runtime-logging.js").createRuntimeLogging; |
|
|
| beforeEach(async () => { |
| vi.clearAllMocks(); |
| loggingMocks.getChildLogger.mockReturnValue(loggingMocks.childLogger); |
| loggingMocks.isFileLogLevelEnabled.mockReturnValue(true); |
| ({ createRuntimeLogging } = await import("./runtime-logging.js")); |
| }); |
|
|
| describe("createRuntimeLogging", () => { |
| it("forwards structured metadata to child loggers", () => { |
| const logging = createRuntimeLogging(); |
| const logger = logging.getChildLogger({ plugin: "discord" }, { level: "warn" }); |
| const meta = { |
| errorName: "Error", |
| errorCauseName: "TypeError", |
| }; |
|
|
| logger.debug?.("debug details", meta); |
| logger.info("info details", meta); |
| logger.warn("warn details", meta); |
| logger.error("error details", meta); |
|
|
| expect(loggingMocks.getChildLogger).toHaveBeenCalledWith( |
| { plugin: "discord" }, |
| { level: "warn" }, |
| ); |
| expect(loggingMocks.childLogger.debug).toHaveBeenCalledWith(meta, "debug details"); |
| expect(loggingMocks.childLogger.info).toHaveBeenCalledWith(meta, "info details"); |
| expect(loggingMocks.childLogger.warn).toHaveBeenCalledWith(meta, "warn details"); |
| expect(loggingMocks.childLogger.error).toHaveBeenCalledWith(meta, "error details"); |
|
|
| logger.info("message without metadata"); |
| logger.warn("message with empty metadata", {}); |
| expect(loggingMocks.childLogger.info).toHaveBeenLastCalledWith("message without metadata"); |
| expect(loggingMocks.childLogger.warn).toHaveBeenLastCalledWith("message with empty metadata"); |
| }); |
|
|
| it("resolves the child logger per call so a runtime log-level change takes effect", () => { |
| const logging = createRuntimeLogging(); |
| |
| const logger = logging.getChildLogger({ module: "mattermost" }); |
|
|
| |
| loggingMocks.isFileLogLevelEnabled.mockReturnValue(false); |
| logger.debug?.("dropped before debug enabled"); |
| expect(loggingMocks.childLogger.debug).not.toHaveBeenCalled(); |
| expect(loggingMocks.getChildLogger).not.toHaveBeenCalled(); |
|
|
| |
| |
| loggingMocks.isFileLogLevelEnabled.mockReturnValue(true); |
| logger.debug?.("written after debug enabled"); |
| expect(loggingMocks.getChildLogger).toHaveBeenCalledWith({ module: "mattermost" }, undefined); |
| expect(loggingMocks.childLogger.debug).toHaveBeenCalledWith("written after debug enabled"); |
| }); |
|
|
| it("pre-gates on the current file level when no override is set", () => { |
| loggingMocks.isFileLogLevelEnabled.mockImplementation((level: string) => level !== "debug"); |
| const logging = createRuntimeLogging(); |
| const logger = logging.getChildLogger({ module: "mattermost" }); |
|
|
| logger.debug?.("debug suppressed at info"); |
| logger.info("info written at info"); |
|
|
| expect(loggingMocks.childLogger.debug).not.toHaveBeenCalled(); |
| expect(loggingMocks.childLogger.info).toHaveBeenCalledWith("info written at info"); |
| }); |
| }); |
|
|