diff --git a/README.md b/README.md index 260e346..b9bc579 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,19 @@ so that it can be easily parsed by tool such as LogDNA. {"level":"warn","message":"this is a message","some-extra-data":"hello","@timestamp":"2019-11-29T21:44:40.463Z"} ``` +## Environment Variable Options + +To suppress some bits of the log to make it less noisy you can set these environment variables: + +* CONSOLE_LOG_JSON_NO_FILE_NAME = 'true' + * Omits `@filename` in log +* CONSOLE_LOG_JSON_NO_PACKAGE_NAME = 'true' + * Omits `@packageName` in log +* CONSOLE_LOG_JSON_NO_TIME_STAMP = 'true' + * Omits `@timestamp` in log +* CONSOLE_LOG_JSON_NO_STACK_FOR_NON_ERROR = 'true' + * Omits `@logCallStack` in log + ## Examples ### 1. Logging an error object diff --git a/package-lock.json b/package-lock.json index e427dd3..274d509 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,6 +66,51 @@ "fastq": "^1.6.0" } }, + "@sinonjs/commons": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.2.0.tgz", + "integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, "@types/app-root-path": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@types/app-root-path/-/app-root-path-1.2.4.tgz", @@ -178,6 +223,21 @@ "@types/node": "*" } }, + "@types/sinon": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.8.tgz", + "integrity": "sha512-IVnI820FZFMGI+u1R+2VdRaD/82YIQTdqLYC9DLPszZuynAJDtCvCtCs3bmyL66s7FqRM3+LPX7DhHnVTaagDw==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz", + "integrity": "sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==", + "dev": true + }, "@types/tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", @@ -1244,6 +1304,12 @@ "verror": "1.10.0" } }, + "just-extend": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", + "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==", + "dev": true + }, "kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -1264,6 +1330,12 @@ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, "log-symbols": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", @@ -1507,6 +1579,19 @@ "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", "dev": true }, + "nise": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", + "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1607,6 +1692,23 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, "pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", @@ -1836,6 +1938,38 @@ "is-arrayish": "^0.3.1" } }, + "sinon": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.0.tgz", + "integrity": "sha512-eSNXz1XMcGEMHw08NJXSyTHIu6qTCOiN8x9ODACmZpNQpr0aXTBXBnI4xTzQzR+TEpOmLiKowGf9flCuKIzsbw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.8.1", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.2.0", + "diff": "^4.0.2", + "nise": "^4.0.4", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index 7f4a267..739313a 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@types/node": "^14.14.2", "@types/request-promise": "^4.1.46", "@types/rimraf": "^3.0.0", + "@types/sinon": "^9.0.8", "chai": "^4.2.0", "cheerio": "^1.0.0-rc.3", "create-ts-index": "^1.13.6", @@ -69,6 +70,7 @@ "request": "^2.88.2", "request-promise": "^4.2.6", "rimraf": "^3.0.2", + "sinon": "^9.2.0", "ts-node": "^9.0.0", "tslint": "^6.1.3", "tslint-config-prettier": "^1.18.0", diff --git a/src/logger.ts b/src/logger.ts index e4efa8b..f2b1704 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -156,7 +156,10 @@ export function FormatErrorObject(object: any) { } // Add timestamp - returnData['@timestamp'] = new Date().toISOString(); + const { CONSOLE_LOG_JSON_NO_TIME_STAMP } = process.env; + if (CONSOLE_LOG_JSON_NO_TIME_STAMP?.toLowerCase() !== 'true') { + returnData['@timestamp'] = new Date().toISOString(); + } // cleanup leading dash in message if (returnData.message && returnData.message.startsWith(' - ')) { @@ -414,12 +417,36 @@ export function logUsingWinston(args: any[], level: LOG_LEVEL) { } const { message, errorObject } = extractParametersFromArguments(args); - Logger.log(level, message, errorObject); + Logger.log(level, message, supressDetailsIfSelected(errorObject)); } catch (err) { ifEverythingFailsLogger('console.log', err); } } +function supressDetailsIfSelected(errorObject: ErrorWithContext | undefined) { + const { CONSOLE_LOG_JSON_NO_STACK_FOR_NON_ERROR } = process.env; + const { CONSOLE_LOG_JSON_NO_FILE_NAME } = process.env; + const { CONSOLE_LOG_JSON_NO_PACKAGE_NAME } = process.env; + + if (errorObject == undefined) { + return undefined; + } + + if (CONSOLE_LOG_JSON_NO_STACK_FOR_NON_ERROR?.toLowerCase() === 'true') { + delete (errorObject as any)['@logCallStack']; + } + + if (CONSOLE_LOG_JSON_NO_FILE_NAME?.toLowerCase() === 'true') { + delete (errorObject as any)['@filename']; + } + + if (CONSOLE_LOG_JSON_NO_PACKAGE_NAME?.toLowerCase() === 'true') { + delete (errorObject as any)['@packageName']; + } + + return errorObject; +} + /** * Each level is given a specific integer priority. * The higher the priority the more important the message is considered to be, diff --git a/test/logger.test.ts b/test/logger.test.ts index 0d3ac51..189f6f2 100644 --- a/test/logger.test.ts +++ b/test/logger.test.ts @@ -11,8 +11,21 @@ import { restoreStdOut, SetLogLevel } from '../src'; +import sinon from 'sinon' describe('logger', () => { + const sandbox = sinon.createSandbox(); + process.env.CONSOLE_LOG_JSON_NO_STACK_FOR_NON_ERROR = '' + process.env.CONSOLE_LOG_JSON_NO_FILE_NAME = '' + process.env.CONSOLE_LOG_JSON_NO_PACKAGE_NAME = '' + process.env.CONSOLE_LOG_JSON_NO_TIME_STAMP = '' + + + + afterEach(() => { + sandbox.restore(); + }) + it('logs error in correct shape', async () => { const {originalWrite, outputText} = overrideStdOut(); await LoggerAdaptToConsole(); @@ -46,6 +59,79 @@ describe('logger', () => { expect(JSON.parse(outputText[1]).errCallStack.startsWith("Error: error object\n at ")).eql(true, "starts with specific text"); }); + it(`omits log call stack if configured in environment variable`, async () => { + sandbox.stub(process.env, 'CONSOLE_LOG_JSON_NO_STACK_FOR_NON_ERROR').value('TRUE'); + const {originalWrite, outputText} = overrideStdOut(); + await LoggerAdaptToConsole(); + try { + // action + await console.log('some log string string'); + } finally { + restoreStdOut(originalWrite); + LoggerRestoreConsole(); + } + + // assert + console.log(outputText[0]); + + const testObj = JSON.parse(stripTimeStamp(outputText[0])); + delete testObj["@filename"]; + delete testObj.errCallStack; + + expect(testObj["@logCallStack"]).eql(undefined); + }) + + it(`does NOT omit log call stack if NOT configured in environment variable`, async () => { + const {originalWrite, outputText} = overrideStdOut(); + await LoggerAdaptToConsole(); + try { + // action + await console.log('some log string string'); + } finally { + restoreStdOut(originalWrite); + LoggerRestoreConsole(); + } + + // assert + console.log(outputText[0]); + + const testObj = JSON.parse(stripTimeStamp(outputText[0])); + delete testObj["@filename"]; + delete testObj.errCallStack; + + expect(testObj["@logCallStack"]).not.eql(undefined); + }) + + + it(`omits multiple bits if configured in environment variable`, async () => { + sandbox.stub(process.env, 'CONSOLE_LOG_JSON_NO_FILE_NAME').value('TRUE'); + sandbox.stub(process.env, 'CONSOLE_LOG_JSON_NO_PACKAGE_NAME').value('TRUE'); + sandbox.stub(process.env, 'CONSOLE_LOG_JSON_NO_TIME_STAMP').value('TRUE'); + sandbox.stub(process.env, 'CONSOLE_LOG_JSON_NO_STACK_FOR_NON_ERROR').value('TRUE'); + + const {originalWrite, outputText} = overrideStdOut(); + await LoggerAdaptToConsole(); + try { + // action + await console.log('some log string string'); + } finally { + restoreStdOut(originalWrite); + LoggerRestoreConsole(); + } + + // assert + console.log(outputText[0]); + + const testObj = JSON.parse(stripTimeStamp(outputText[0])); + delete testObj["@filename"]; + delete testObj.errCallStack; + + expect(testObj["@logCallStack"]).eql(undefined); + }) + + + + it('logs error in correct shape using console.log', async () => { const {originalWrite, outputText} = overrideStdOut(); await LoggerAdaptToConsole();