Skip to content

Commit 8bc79d1

Browse files
committed
updated hooks for nextjs
1 parent b7cd166 commit 8bc79d1

File tree

2 files changed

+68
-97
lines changed

2 files changed

+68
-97
lines changed

lib/instrumentation-security/hooks/nextjs/nr-next.js

Lines changed: 67 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -8,115 +8,86 @@ const requestManager = require("../../core/request-manager");
88
const API = require("../../../nr-security-api");
99
const logger = API.getLogger();
1010

11-
const fs = require('fs');
12-
const path = require('path');
11+
const semver = require('semver')
1312

1413
module.exports = function initialize(shim, nextjs) {
15-
const pkgVersion = shim.require('package.json').version;
16-
logger.info("Instrumenting nextjs", pkgVersion);
14+
const nextVersion = shim.require('./package.json').version
15+
logger.info("Instrumenting nextjs", nextVersion);
1716

18-
const utils = shim.require('./dist/next-server/lib/router/utils');
17+
const nextServer = nextjs.default;
18+
hookRunAPI(shim, nextServer.prototype, nextVersion);
19+
}
1920

20-
if (utils) {
21-
getRouteMatcherHook(utils);
22-
}
21+
/**
22+
* Wrapper for Server.prototype.runApi
23+
* @param {*} shim
24+
* @param {*} mod
25+
* @param {*} nextVersion
26+
*/
27+
function hookRunAPI(shim, mod, nextVersion) {
28+
shim.wrap(mod, 'runApi', function wrapRunApi(shim, originalFn) {
29+
if (!shim.isFunction(originalFn)) {
30+
return originalFn
31+
}
32+
logger.debug("Instrumenting Server.prototype.runApi");
33+
return function wrappedRunApi() {
34+
try {
35+
const { page, params } = extractAttrs(arguments, nextVersion)
36+
extractParams(shim, page, params);
37+
} catch (error) {
38+
logger.debug("Error while processing path paramters");
39+
}
2340

24-
const routeMatcher = shim.require('./dist/shared/lib/router/utils/route-matcher.js');
41+
return originalFn.apply(this, arguments)
42+
}
43+
})
44+
}
2545

26-
if (routeMatcher) {
27-
getRouteMatcherHook(routeMatcher);
46+
/**
47+
* Extracts the page and params from an API request
48+
*
49+
* @param {object} args arguments to runApi
50+
* @param {string} version next.js version
51+
* @returns {object} { page, params }
52+
*/
53+
function extractAttrs(args, version) {
54+
let params
55+
let page
56+
if (semver.gte(version, '13.4.13')) {
57+
const [, , , match] = args
58+
page = match?.definition?.pathname
59+
params = { ...match?.params }
60+
} else {
61+
;[, , , params, page] = args
2862
}
2963

30-
/**
31-
* wrapper for route-matcher.getRouteMatcher
32-
* @param {*} mod
33-
*/
34-
function getRouteMatcherHook(mod) {
35-
shim.wrap(mod, 'getRouteMatcher', function wrapGetRouterMatcher(shim, fn) {
36-
if (!shim.isFunction(fn)) {
37-
return fn
38-
}
39-
logger.debug(`Instrumenting route-matcher.getRouteMatcher`)
40-
return function wrappedGetRouterMatcher() {
41-
let result = fn.apply(this, arguments)
42-
if (!shim.isFunction(result)) {
43-
return result;
44-
}
45-
let original = result;
46-
result = function () {
47-
const res = original.apply(this, arguments);
48-
extractParams(this, res);
49-
return res;
50-
}
51-
return result
52-
}
53-
})
54-
}
64+
return { params, page }
65+
}
5566

56-
/**
57-
* Utility to extract path params
58-
* @param {*} obj
59-
* @param {*} params
60-
*/
61-
function extractParams(obj, params) {
62-
try {
63-
const transaction = shim.tracer.getTransaction();
64-
if (transaction) {
65-
let request = requestManager.getRequestFromId(transaction.id);
66-
Object.keys(params).forEach(function (key) {
67-
if (params[key]) {
68-
if (!request.parameterMap[key]) {
69-
request.parameterMap[key] = new Array(params[key].toString());
70-
requestManager.setRequest(transaction.id, request);
71-
}
67+
/**
68+
* Utility to extract path params
69+
* @param {*} page
70+
* @param {*} params
71+
*/
72+
function extractParams(shim, page, params) {
73+
try {
74+
const transaction = shim.tracer.getTransaction();
75+
if (transaction) {
76+
let request = requestManager.getRequestFromId(transaction.id);
77+
Object.keys(params).forEach(function (key) {
78+
if (params[key]) {
79+
if (!request.parameterMap[key]) {
80+
request.parameterMap[key] = new Array(params[key].toString());
81+
requestManager.setRequest(transaction.id, request);
7282
}
73-
});
74-
if (request && obj && obj.page) {
75-
request.uri = obj.page;
76-
requestManager.setRequest(transaction.id, request);
7783
}
84+
});
85+
if (request && page) {
86+
request.uri = page;
87+
requestManager.setRequest(transaction.id, request);
7888
}
79-
} catch (error) {
8089
}
90+
} catch (error) {
8191
}
82-
8392
}
8493

85-
/**
86-
* Utility to scan pages directory to get all avaible routes
87-
* @param {*} dir
88-
* @returns
89-
*/
90-
const getAllAPIEndpoints = (dir) => {
91-
const apiEndpoints = [];
92-
93-
const scanDirectory = (currentDir) => {
94-
const files = fs.readdirSync(currentDir);
95-
96-
files.forEach((file) => {
97-
const filePath = path.join(currentDir, file);
98-
const isDirectory = fs.statSync(filePath).isDirectory();
99-
100-
if (isDirectory) {
101-
scanDirectory(filePath);
102-
} else {
103-
const apiEndpoint = filePath.replace(`${dir}/`, '/').replace(/\.js$/, '');
104-
apiEndpoints.push(apiEndpoint);
105-
}
106-
});
107-
};
108-
109-
scanDirectory(dir);
110-
return apiEndpoints;
111-
};
112-
113-
114-
//TODO need to update for API endpoints
115-
// try {
116-
// const appRoot = API.getSecAgent().applicationInfo.serverInfo.deployedApplications[0].deployedPath;
117-
// const searchPath = appRoot + '/.next/server/pages';
118-
// const allAPIEndpoints = getAllAPIEndpoints(searchPath);
119-
// } catch (error) {
120-
// logger.debug("Error while getting all API end points for next.js", error);
121-
// }
122-

lib/instrumentation-security/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ newrelic.instrument({
262262
})
263263

264264
newrelic.instrumentWebframework({
265-
moduleName: 'next',
265+
moduleName: 'next/dist/server/next-server',
266266
isEsm: true,
267267
onRequire: require('./hooks/nextjs/nr-next'),
268268
onError: function intrumentErrorHandler(err) {

0 commit comments

Comments
 (0)