diff --git a/README.md b/README.md index 8630092..c63af52 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ logger.fatal(new Error("I am a pretty Error with a stacktrace.")); ## All Features - **Universal:** Works in browsers and Node.js -- **Tested:** 100% code coverage, CI +- **Tested:** Great code coverage, CI - **Super customizable:** Every aspect can be overwritten - **Fully typed:** Written in TypeScript, with native TypeScript support - **Default log level:** `silly`, `trace`, `debug`, `info`, `warn`, `error`, `fatal` (different colors) diff --git a/docs/README.md b/docs/README.md index 3949d1f..c63af52 100644 --- a/docs/README.md +++ b/docs/README.md @@ -167,7 +167,7 @@ logger.fatal(new Error("I am a pretty Error with a stacktrace.")); ## All Features - **Universal:** Works in browsers and Node.js -- **Tested:** 100% code coverage, CI +- **Tested:** Great code coverage, CI - **Super customizable:** Every aspect can be overwritten - **Fully typed:** Written in TypeScript, with native TypeScript support - **Default log level:** `silly`, `trace`, `debug`, `info`, `warn`, `error`, `fatal` (different colors) @@ -686,7 +686,7 @@ For `pretty` logs: For `JSON` logs (no formatting happens here): ```typescript const logger = new Logger({ - type: "pretty", + type: "json", overwrite: { transportJSON: (logObjWithMeta: any) => { // transport the LogObj to console, StdOut, a file or an external service diff --git a/examples/nodejs/index2.ts b/examples/nodejs/index2.ts index 436268c..a712fe7 100644 --- a/examples/nodejs/index2.ts +++ b/examples/nodejs/index2.ts @@ -119,3 +119,14 @@ class CustomError extends Error { const err = new CustomError("a", "b"); logger.error(err); + +console.log("***********"); +logger.debug(null); +logger.debug(undefined); +logger.debug("*", undefined); +console.log("###############"); +//jsonLogger.debug(null); +jsonLogger.debug(undefined); +//jsonLogger.debug('*', undefined); +console.log("###############"); +logger.debug(new URL("https://www.test.de")); diff --git a/package-lock.json b/package-lock.json index e5e99d7..cba2cfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "tslog", - "version": "4.9.1", + "version": "4.9.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "tslog", - "version": "4.9.1", + "version": "4.9.2", "license": "MIT", "devDependencies": { "@jest/types": "^28.1.3", diff --git a/package.json b/package.json index ef6216a..89c0666 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tslog", - "version": "4.9.1", + "version": "4.9.2", "description": "Extensible TypeScript Logger for Node.js and Browser.", "author": "Eugene (https://fullstack.build)", "license": "MIT", diff --git a/src/BaseLogger.ts b/src/BaseLogger.ts index 6406101..c5cc026 100644 --- a/src/BaseLogger.ts +++ b/src/BaseLogger.ts @@ -213,7 +213,13 @@ export class BaseLogger { return Object.getOwnPropertyNames(source).reduce((o, prop) => { o[prop] = keys.includes(this.settings?.maskValuesOfKeysCaseInsensitive !== true ? prop : prop.toLowerCase()) ? this.settings.maskPlaceholder - : this._recursiveCloneAndMaskValuesOfKeys((source as Record)[prop], keys, seen); + : (() => { + try { + return this._recursiveCloneAndMaskValuesOfKeys((source as Record)[prop], keys, seen); + } catch (e) { + return null; + } + })(); return o; }, baseObject) as T; } else { diff --git a/src/runtime/browser/index.ts b/src/runtime/browser/index.ts index bbd7854..d1e58d8 100644 --- a/src/runtime/browser/index.ts +++ b/src/runtime/browser/index.ts @@ -62,8 +62,7 @@ export function getCallerStackFrame(stackDepthLevel: number, error: Error = Erro } export function getErrorTrace(error: Error): IStackFrame[] { - return (error as Error)?.stack - ?.split("\n") + return ((error as Error)?.stack?.split("\n") ?? []) ?.filter((line: string) => !line.includes("Error: ")) ?.reduce((result: IStackFrame[], line: string) => { result.push(stackLineToStackFrame(line)); diff --git a/src/runtime/browser/util.inspect.polyfil.ts b/src/runtime/browser/util.inspect.polyfil.ts index 26a3649..9f15b1f 100644 --- a/src/runtime/browser/util.inspect.polyfil.ts +++ b/src/runtime/browser/util.inspect.polyfil.ts @@ -63,7 +63,7 @@ function isBoolean(arg: unknown) { } function isUndefined(arg: unknown) { - return arg == null; + return arg === undefined; } function stylizeNoColor(str: string) { @@ -377,19 +377,19 @@ function reduceToSingleString(output: string[], base: string, braces: string[]): return braces[0] + (base === "" ? "" : base + "\n") + " " + output.join(",\n ") + " " + braces[1]; } -function _extend(origin: object, add: object) { +function _extend(origin: object, add: object): object { + const typedOrigin = { ...origin } as { [key: string]: unknown }; // Don't do anything if add isn't an object if (!add || !isObject(add)) return origin; - const clonedOrigin = { ...origin } as { [key: string]: unknown }; const clonedAdd = { ...add } as { [key: string]: unknown }; const keys = Object.keys(add); let i = keys.length; while (i--) { - clonedOrigin[keys[i]] = clonedAdd[keys[i]]; + typedOrigin[keys[i]] = clonedAdd[keys[i]]; } - return origin; + return typedOrigin; } export function formatWithOptions(inspectOptions: InspectOptions, ...args: unknown[]) { diff --git a/src/runtime/nodejs/index.ts b/src/runtime/nodejs/index.ts index ccd4b18..6aa0793 100644 --- a/src/runtime/nodejs/index.ts +++ b/src/runtime/nodejs/index.ts @@ -168,6 +168,9 @@ export function transportJSON(json: LogObj & ILogObjMeta): void { if (typeof value === "bigint") { return `${value}`; } + if (typeof value === "undefined") { + return "[undefined]"; + } return value; }); } diff --git a/tests/Browser/1_json.test.ts b/tests/Browser/1_json.test.ts index ffb77e2..dcac704 100644 --- a/tests/Browser/1_json.test.ts +++ b/tests/Browser/1_json.test.ts @@ -75,4 +75,32 @@ describe("Browser: JSON: Log level", () => { expect(consoleOutput).toContain("Foo bar"); }); + + it("pretty undefined", async () => { + await page.evaluate(() => { + // @ts-ignore + const logger = new tslog.Logger({ type: "pretty", stylePrettyLogs: false }); + logger.info(undefined); + }); + expect(consoleOutput).toContain("undefined"); + }); + + it("pretty null", async () => { + await page.evaluate(() => { + // @ts-ignore + const logger = new tslog.Logger({ type: "pretty", stylePrettyLogs: false }); + logger.info(null); + }); + expect(consoleOutput).toContain("null"); + }); + + it("pretty nullish", async () => { + await page.evaluate(() => { + // @ts-ignore + const logger = new tslog.Logger({ type: "pretty", stylePrettyLogs: false }); + logger.info({ foo: null, bar: undefined }); + }); + expect(consoleOutput).toContain("null"); + expect(consoleOutput).toContain("undefined"); + }); }); diff --git a/tests/Nodejs/4_json_Log_Types.test.ts b/tests/Nodejs/4_json_Log_Types.test.ts index c750e4c..81396cc 100644 --- a/tests/Nodejs/4_json_Log_Types.test.ts +++ b/tests/Nodejs/4_json_Log_Types.test.ts @@ -20,6 +20,26 @@ describe("JSON: Log Types", () => { expect(getConsoleLog()).toContain('"1":"Test2"'); }); + it("pretty undefined", async () => { + const logger = new Logger({ type: "json" }); + logger.info(undefined); + expect(getConsoleLog()).toContain('"0":"[undefined]"'); + }); + + it("pretty null", async () => { + const logger = new Logger({ type: "json" }); + logger.info(null); + expect(getConsoleLog()).toContain('"0":null'); + }); + + it("pretty nullish", async () => { + const logger = new Logger({ type: "json" }); + logger.info({ foo: null, bar: undefined }); + + expect(getConsoleLog()).toContain('"foo":null'); + expect(getConsoleLog()).toContain('"bar":"[undefined]"'); + }); + test("boolean", (): void => { const logger = new Logger({ type: "json" }); logger.log(1234, "testLevel", true); diff --git a/tests/Nodejs/5_pretty_Log_Types.test.ts b/tests/Nodejs/5_pretty_Log_Types.test.ts index fd7564b..c1ee44f 100644 --- a/tests/Nodejs/5_pretty_Log_Types.test.ts +++ b/tests/Nodejs/5_pretty_Log_Types.test.ts @@ -33,6 +33,28 @@ describe("Pretty: Log Types", () => { expect(getConsoleLog()).toContain("Test1 Test2"); }); + it("pretty undefined", async () => { + const logger = new Logger({ type: "pretty", stylePrettyLogs: false }); + logger.info(undefined); + + expect(getConsoleLog()).toContain("undefined"); + }); + + it("pretty null", async () => { + const logger = new Logger({ type: "pretty", stylePrettyLogs: false }); + logger.info(null); + + expect(getConsoleLog()).toContain("null"); + }); + + it("pretty nullish", async () => { + const logger = new Logger({ type: "pretty", stylePrettyLogs: false }); + logger.info({ foo: null, bar: undefined }); + + expect(getConsoleLog()).toContain("null"); + expect(getConsoleLog()).toContain("undefined"); + }); + test("boolean", (): void => { const logger = new Logger({ type: "pretty" }); logger.log(1234, "testLevel", true); @@ -45,6 +67,12 @@ describe("Pretty: Log Types", () => { expect(getConsoleLog()).toContain("555"); }); + test("null", (): void => { + const logger = new Logger({ type: "pretty" }); + logger.log(1234, "testLevel", null); + expect(getConsoleLog()).toContain("null"); + }); + test("Array, stylePrettyLogs: false", (): void => { const logger = new Logger({ type: "pretty", stylePrettyLogs: false }); logger.log(1234, "testLevel", [1, 2, 3, "test"]); @@ -94,6 +122,27 @@ describe("Pretty: Log Types", () => { expect(getConsoleLog()).toContain("https://example2.com/"); }); + test("Date", (): void => { + const logger = new Logger({ type: "pretty" }); + const date = new Date(0); + logger.log(1234, "testLevel", date); + expect(getConsoleLog()).toContain("1970-01-01T00:00:00.000Z"); + }); + + test("Map", (): void => { + const logger = new Logger({ type: "pretty" }); + const map = new Map(); + logger.log(1234, "testLevel", map); + expect(getConsoleLog()).toContain("Map(0) {}"); + }); + + test("Set", (): void => { + const logger = new Logger({ type: "pretty" }); + const set = new Set(); + logger.log(1234, "testLevel", set); + expect(getConsoleLog()).toContain("Set(0) {}"); + }); + test("String, Object", (): void => { const logger = new Logger({ type: "pretty" }); logger.log(1234, "testLevel", "test", { test: true, nested: { 1: false } });