mirror of
https://github.com/bitwarden/browser
synced 2026-02-03 18:23:57 +00:00
add comments and test coverage to logging module
This commit is contained in:
@@ -7,10 +7,37 @@ export { LogLevel } from "./log-level";
|
||||
export { ConsoleLogService } from "./console-log.service";
|
||||
export { SemanticLogger } from "./semantic-logger.abstraction";
|
||||
|
||||
/** Creates a semantic logger.
|
||||
* @param context all logs emitted by the logger are extended with
|
||||
* these fields.
|
||||
* @remarks The `message`, `level`, `provider`, and `content` fields
|
||||
* are reserved for use by the semantic logging system.
|
||||
/**
|
||||
* Creates a semantic logger with a fixed context that is included in all log messages.
|
||||
*
|
||||
* @param context - Contextual metadata that will be included in every log entry
|
||||
* emitted by the returned logger. This is used to identify the source or scope
|
||||
* of log messages (e.g., `{ type: "ImportService" }` or `{ accountId: "123" }`).
|
||||
*
|
||||
* @returns A SemanticLogger instance that includes the provided context in all log output.
|
||||
*
|
||||
* @remarks
|
||||
* By convention, avoid using the following field names in the context object, as they
|
||||
* may conflict with fields added by the semantic logging implementation:
|
||||
* - `message` - The log message text
|
||||
* - `level` - The log level (debug, info, warn, error, panic)
|
||||
* - `provider` - The logging provider identifier
|
||||
* - `content` - Additional data passed to individual log calls
|
||||
*
|
||||
* Note: These field names are not enforced at compile-time or runtime, but using them
|
||||
* may result in unexpected behavior or field name collisions in log output.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Create a logger for a service
|
||||
* const log = logProvider({ type: "ImportService" });
|
||||
*
|
||||
* // All logs from this logger will include { type: "ImportService" }
|
||||
* log.debug("Starting import");
|
||||
* // Output: { type: "ImportService", level: "debug", message: "Starting import" }
|
||||
*
|
||||
* log.info({ itemCount: 42 }, "Import complete");
|
||||
* // Output: { type: "ImportService", level: "info", content: { itemCount: 42 }, message: "Import complete" }
|
||||
* ```
|
||||
*/
|
||||
export type LogProvider = <Context extends object>(context: Jsonify<Context>) => SemanticLogger;
|
||||
|
||||
@@ -1,8 +1,73 @@
|
||||
import * as lib from "./index";
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
describe("logging", () => {
|
||||
// This test will fail until something is exported from index.ts
|
||||
it("should work", () => {
|
||||
expect(lib).toBeDefined();
|
||||
import * as lib from "./index";
|
||||
import { SemanticLogger } from "./index";
|
||||
|
||||
describe("logging module", () => {
|
||||
describe("public API", () => {
|
||||
it("should export LogService", () => {
|
||||
expect(lib.LogService).toBeDefined();
|
||||
});
|
||||
|
||||
it("should export LogLevel", () => {
|
||||
expect(lib.LogLevel).toBeDefined();
|
||||
});
|
||||
|
||||
it("should export ConsoleLogService", () => {
|
||||
expect(lib.ConsoleLogService).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("SemanticLogger", () => {
|
||||
let logger: SemanticLogger;
|
||||
|
||||
beforeEach(() => {
|
||||
logger = mock<SemanticLogger>();
|
||||
});
|
||||
|
||||
describe("logging methods", () => {
|
||||
it("should accept a message string", () => {
|
||||
logger.debug("debug message");
|
||||
logger.info("info message");
|
||||
logger.warn("warn message");
|
||||
logger.error("error message");
|
||||
|
||||
expect(logger.debug).toHaveBeenCalledWith("debug message");
|
||||
expect(logger.info).toHaveBeenCalledWith("info message");
|
||||
expect(logger.warn).toHaveBeenCalledWith("warn message");
|
||||
expect(logger.error).toHaveBeenCalledWith("error message");
|
||||
});
|
||||
|
||||
it("should accept content object and optional message", () => {
|
||||
logger.debug({ step: 1 }, "processing step");
|
||||
logger.info({ count: 42 }, "items processed");
|
||||
logger.warn({ threshold: 100 }, "approaching limit");
|
||||
logger.error({ code: 500 }, "server error");
|
||||
|
||||
expect(logger.debug).toHaveBeenCalledWith({ step: 1 }, "processing step");
|
||||
expect(logger.info).toHaveBeenCalledWith({ count: 42 }, "items processed");
|
||||
expect(logger.warn).toHaveBeenCalledWith({ threshold: 100 }, "approaching limit");
|
||||
expect(logger.error).toHaveBeenCalledWith({ code: 500 }, "server error");
|
||||
});
|
||||
});
|
||||
|
||||
describe("panic", () => {
|
||||
beforeEach(() => {
|
||||
logger.panic = jest.fn((content: any, msg?: string) => {
|
||||
const errorMsg = msg || (typeof content === "string" ? content : "panic");
|
||||
throw new Error(errorMsg);
|
||||
}) as any;
|
||||
});
|
||||
|
||||
it("should throw when called with a message", () => {
|
||||
expect(() => logger.panic("critical error")).toThrow("critical error");
|
||||
});
|
||||
|
||||
it("should throw when called with content and message", () => {
|
||||
expect(() => logger.panic({ reason: "invalid state" }, "system panic")).toThrow(
|
||||
"system panic",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user