diff --git a/packages/collector/test/integration/currencies/logging/bunyan/bunyanApp.js b/packages/collector/test/integration/currencies/logging/bunyan/bunyanApp.js index bed967b533..9cf507b219 100644 --- a/packages/collector/test/integration/currencies/logging/bunyan/bunyanApp.js +++ b/packages/collector/test/integration/currencies/logging/bunyan/bunyanApp.js @@ -100,6 +100,27 @@ app.get('/child-error', (req, res) => { finish(res); }); +app.get('/error-with-cause', (req, res) => { + const causeError = new Error('This is the cause error'); + const mainError = new Error('This is the main error', { cause: causeError }); + logger.error(mainError); + finish(res); +}); + +app.get('/error-with-cause-and-extra-string', (req, res) => { + const causeError = new Error('This is the cause error'); + const mainError = new Error('This is the main error', { cause: causeError }); + logger.error(mainError, 'Error message - should be traced.'); + finish(res); +}); + +app.get('/nested-error-with-cause', (req, res) => { + const causeError = new Error('This is the cause error'); + const mainError = new Error('This is the main error', { cause: causeError }); + logger.error({ foo: 'bar', err: mainError }, 'Error message - should be traced.'); + finish(res); +}); + function finish(res) { fetch(`http://127.0.0.1:${agentPort}/ping`).then(() => { res.sendStatus(200); diff --git a/packages/collector/test/integration/currencies/logging/bunyan/bunyanApp.mjs b/packages/collector/test/integration/currencies/logging/bunyan/bunyanApp.mjs index dd9bbb163a..e1ea7a5a15 100644 --- a/packages/collector/test/integration/currencies/logging/bunyan/bunyanApp.mjs +++ b/packages/collector/test/integration/currencies/logging/bunyan/bunyanApp.mjs @@ -101,6 +101,27 @@ app.get('/child-error', (req, res) => { finish(res); }); +app.get('/error-with-cause', (req, res) => { + const causeError = new Error('This is the cause error'); + const mainError = new Error('This is the main error', { cause: causeError }); + logger.error(mainError); + finish(res); +}); + +app.get('/error-with-cause-and-extra-string', (req, res) => { + const causeError = new Error('This is the cause error'); + const mainError = new Error('This is the main error', { cause: causeError }); + logger.error(mainError, 'Error message - should be traced.'); + finish(res); +}); + +app.get('/nested-error-with-cause', (req, res) => { + const causeError = new Error('This is the cause error'); + const mainError = new Error('This is the main error', { cause: causeError }); + logger.error({ foo: 'bar', err: mainError }, 'Error message - should be traced.'); + finish(res); +}); + function finish(res) { fetch(`http://127.0.0.1:${agentPort}/ping`).then(() => { res.sendStatus(200); diff --git a/packages/collector/test/integration/currencies/logging/bunyan/test_base.js b/packages/collector/test/integration/currencies/logging/bunyan/test_base.js index 9a0beece1f..ffed9dc2f9 100644 --- a/packages/collector/test/integration/currencies/logging/bunyan/test_base.js +++ b/packages/collector/test/integration/currencies/logging/bunyan/test_base.js @@ -76,10 +76,10 @@ module.exports = function (name, version, isLatest) { it('must trace fatal', () => runTest('fatal', true, 'Fatal message - should be traced.', controls)); it("must capture an error object's message", () => - runTest('error-object-only', true, 'This is an error.', controls)); + runTest('error-object-only', true, 'Error: This is an error.', controls)); it("must capture a nested error object's message", async () => { - await runTest('nested-error-object-only', true, 'This is a nested error.', controls); + await runTest('nested-error-object-only', true, 'Error: This is a nested error.', controls); }); it('must serialize random object', () => runTest('error-random-object-only', true, '{"foo":"[Object]"}', controls)); @@ -96,14 +96,19 @@ module.exports = function (name, version, isLatest) { )); it("must capture an error object's message and an additional string", () => - runTest('error-object-and-string', true, 'This is an error. -- Error message - should be traced.', controls)); + runTest( + 'error-object-and-string', + true, + 'Error: This is an error. -- Error message - should be traced.', + controls + )); it("must capture a nested error object's message and an additional string", () => runTest( 'nested-error-object-and-string', true, // eslint-disable-next-line max-len - 'This is a nested error. -- Error message - should be traced.', + 'Error: This is a nested error. -- Error message - should be traced.', controls )); @@ -118,6 +123,25 @@ module.exports = function (name, version, isLatest) { it('must trace child logger error', () => runTest('child-error', true, 'Child logger error message - should be traced.', controls)); + it('must trace an error with cause property', () => + runTest('error-with-cause', true, 'Error: This is the cause error', controls)); + + it('must trace an error with cause property and extra string', () => + runTest( + 'error-with-cause-and-extra-string', + true, + 'Error: This is the cause error -- Error message - should be traced.', + controls + )); + + it('must trace a nested error with cause property and extra string', () => + runTest( + 'nested-error-with-cause', + true, + 'Error: This is the cause error -- Error message - should be traced.', + controls + )); + it('[suppression] should not trace', async function () { await trigger('warn', controls, { 'X-INSTANA-L': '0' }); diff --git a/packages/core/src/tracing/instrumentation/logging/bunyan.js b/packages/core/src/tracing/instrumentation/logging/bunyan.js index 7c3acd329d..cf663e065a 100644 --- a/packages/core/src/tracing/instrumentation/logging/bunyan.js +++ b/packages/core/src/tracing/instrumentation/logging/bunyan.js @@ -67,27 +67,17 @@ function instrumentedLog(ctx, originalLog, originalArgs, markAsError) { if (typeof fields === 'string') { message = fields; - } else if (fields && typeof fields.message === 'string' && typeof message === 'string') { - message = `${fields.message} -- ${message}`; + } else if (fields instanceof Error) { + const errorMessage = tracingUtil.extractErrorMessage(fields); + message = typeof message === 'string' ? `${errorMessage} -- ${message}` : errorMessage; + } else if (fields?.err instanceof Error) { + const errorMessage = tracingUtil.extractErrorMessage(fields.err); + message = typeof message === 'string' ? `${errorMessage} -- ${message}` : errorMessage; + } else if (fields?.err && typeof fields.err.message === 'string') { + message = typeof message === 'string' ? `${fields.err.message} -- ${message}` : fields.err.message; } else if (fields && typeof fields.message === 'string') { - message = fields.message; - } else if ( - fields && - fields.err && - typeof fields.err === 'object' && - typeof fields.err.message === 'string' && - typeof message === 'string' - ) { - // Support for fields.err.message based on the last example given in - // https://github.com/trentm/node-bunyan#log-method-api - quote: "To pass in an Error *and* other fields, use the - // `err` field name for the Error instance..." - message = `${fields.err.message} -- ${message}`; - } else if (fields && fields.err && typeof fields.err === 'object' && typeof fields.err.message === 'string') { - message = fields.err.message; - } else if (typeof fields === 'object') { - // CASE: we try our best to serialize logged objects - // we do not want to directly call JSON.stringify because we do not know how big the object is and - // there might be possible circular dependencies in the object. + message = typeof message === 'string' ? `${fields.message} -- ${message}` : fields.message; + } else if (fields && typeof fields === 'object') { const maxNoOfKeys = 100; const obj = {};