diff --git a/CHANGELOG.md b/CHANGELOG.md index 198fb09681..11bb401f11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + - Expose a debugging action to learn about loaded modules. + - Allow retrieval of `package.json` files. + ## 1.41.0 - Add PostgreSQL instrumentation ([pg](https://www.npmjs.com/package/pg)). diff --git a/src/actions/getModuleAnalysis.js b/src/actions/getModuleAnalysis.js new file mode 100644 index 0000000000..74668483c6 --- /dev/null +++ b/src/actions/getModuleAnalysis.js @@ -0,0 +1,12 @@ +'use strict'; + +exports.getModuleAnalysis = function(request, multiCb) { + multiCb({ + data: { + 'cwd': process.cwd(), + 'require.main.filename': require.main ? require.main.filename : undefined, + 'require.main.paths': require.main ? require.main.paths : undefined, + 'require.cache': Object.keys(require.cache) + } + }); +}; diff --git a/src/actions/source.js b/src/actions/source.js index d37277caac..4a7b6eb3de 100644 --- a/src/actions/source.js +++ b/src/actions/source.js @@ -4,7 +4,7 @@ var fs = require('fs'); var logger = require('../logger').getLogger('actions/profiling/cpu'); -var validFileRequests = /\.(js|ts|jsx)$/i; +var validFileRequests = /\.(js|ts|jsx)$|(^|\/)package\.json$/i; exports.getSourceFile = function(request, multiCb) { if (!request.args.file.match(validFileRequests)) { @@ -21,7 +21,7 @@ exports.getSourceFile = function(request, multiCb) { function readFile(request, multiCb) { fs.readFile(request.args.file, {encoding: 'utf8'}, function(error, content) { if (error) { - logger.warn( + logger.debug( 'Failed to retrieve source file for user request: %s.', request.args.file, {error: error} diff --git a/src/agent/requestHandler.js b/src/agent/requestHandler.js index 7f64e4da34..9669db4958 100644 --- a/src/agent/requestHandler.js +++ b/src/agent/requestHandler.js @@ -6,7 +6,8 @@ var logger = require('../logger').getLogger('agent/requestHandler'); var agentConnection = require('../agentConnection'); var actionMapping = { - 'node.source': require('../actions/source').getSourceFile + 'node.source': require('../actions/source').getSourceFile, + 'node.getModuleAnalysis': require('../actions/getModuleAnalysis').getModuleAnalysis }; if (semver.satisfies(process.versions.node, '>=4.0.0')) { diff --git a/test/actions/getModuleAnalysis_test.js b/test/actions/getModuleAnalysis_test.js new file mode 100644 index 0000000000..8bd9177c4b --- /dev/null +++ b/test/actions/getModuleAnalysis_test.js @@ -0,0 +1,55 @@ +'use strict'; + +var expect = require('chai').expect; +var semver = require('semver'); + +var supportedVersion = require('../../src/tracing/index').supportedVersion; +var config = require('../config'); +var utils = require('../utils'); + +describe('actions/getModuleAnalysis', function() { + if (semver.satisfies(process.versions.node, '<4')) { + return; + } + + // controls require features that aren't available in early Node.js versions + var expressControls = require('../apps/expressControls'); + var agentStubControls = require('../apps/agentStubControls'); + + this.timeout(config.getTestTimeout()); + + agentStubControls.registerTestHooks(); + expressControls.registerTestHooks({ + enableTracing: supportedVersion(process.versions.node) + }); + + beforeEach(function() { + return agentStubControls.waitUntilAppIsCompletelyInitialized(expressControls.getPid()); + }); + + it('must receive module analysis', function() { + var messageId = 'a'; + return agentStubControls.addRequestForPid( + expressControls.getPid(), + { + action: 'node.getModuleAnalysis', + messageId: messageId, + args: {} + } + ) + .then(function() { + return utils.retry(function() { + return agentStubControls.getResponses() + .then(function(responses) { + utils.expectOneMatching(responses, function(response) { + expect(response.messageId).to.equal(messageId); + expect(response.data.data.cwd).to.be.a('string'); + expect(response.data.data['require.main.filename']).to.be.a('string'); + expect(response.data.data['require.main.paths']).to.be.an('array'); + expect(response.data.data['require.cache']).to.be.an('array'); + }); + }); + }); + }); + }); +}); diff --git a/test/actions/source_test.js b/test/actions/source_test.js index e872fcf5f0..3cb0ce808c 100644 --- a/test/actions/source_test.js +++ b/test/actions/source_test.js @@ -15,7 +15,7 @@ describe('actions/source', function() { } // controls require features that aren't available in early Node.js versions - var expressControls = require('../apps/expressElasticsearchControls'); + var expressControls = require('../apps/expressControls'); var agentStubControls = require('../apps/agentStubControls'); this.timeout(config.getTestTimeout()); @@ -55,7 +55,7 @@ describe('actions/source', function() { }); }); - it('must not allow JSON requests', function() { + it('must allow package.json requests', function() { var messageId = 'a'; return agentStubControls.addRequestForPid( expressControls.getPid(), @@ -67,6 +67,32 @@ describe('actions/source', function() { } } ) + .then(function() { + return utils.retry(function() { + return agentStubControls.getResponses() + .then(function(responses) { + utils.expectOneMatching(responses, function(response) { + expect(response.messageId).to.equal(messageId); + expect(response.data.data).to.be.a('string'); + expect(response.data.data).to.match(/"name": "instana-nodejs-sensor"/i); + }); + }); + }); + }); + }); + + it('must not allow JSON requests', function() { + var messageId = 'a'; + return agentStubControls.addRequestForPid( + expressControls.getPid(), + { + action: 'node.source', + messageId: messageId, + args: { + file: path.join(process.cwd(), 'foo.json') + } + } + ) .then(function() { return utils.retry(function() { return agentStubControls.getResponses()