@gasket/plugin-elastic-apm 6.46.8 → 6.47.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/configure.js +51 -0
- package/lib/cookies.js +21 -20
- package/lib/index.d.ts +19 -8
- package/lib/index.js +37 -91
- package/lib/middleware.js +18 -19
- package/lib/preboot.js +32 -0
- package/package.json +5 -5
package/lib/configure.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/// <reference types="@gasket/plugin-command" />
|
|
2
|
+
|
|
3
|
+
const isDefined = (o) => typeof o !== 'undefined';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Determines if the Elastic APM agent has sufficient config to be active
|
|
7
|
+
* @param {import('./index').ExtendedAgentConfigOptions} config Apm agent config
|
|
8
|
+
* @param {NodeJS.ProcessEnv} env Environment variables
|
|
9
|
+
* @returns {boolean} A combined config object
|
|
10
|
+
*/
|
|
11
|
+
const isActive = (config, env) => {
|
|
12
|
+
const { active, serverUrl, secretToken } = config;
|
|
13
|
+
|
|
14
|
+
if (active || env.ELASTIC_APM_ACTIVE) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const combined = {
|
|
19
|
+
serverUrl: serverUrl || env.ELASTIC_APM_SERVER_URL,
|
|
20
|
+
secretToken: secretToken || env.ELASTIC_APM_SECRET_TOKEN
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
if (combined.serverUrl && combined.secretToken) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** @type {import('@gasket/engine').HookHandler<'configure'>} */
|
|
31
|
+
module.exports = async function configure(gasket, config) {
|
|
32
|
+
const { logger } = gasket;
|
|
33
|
+
config.elasticAPM = config.elasticAPM || {};
|
|
34
|
+
|
|
35
|
+
const { serverUrl, secretToken } = config.elasticAPM;
|
|
36
|
+
if (isDefined(serverUrl)) {
|
|
37
|
+
logger.notice(
|
|
38
|
+
'DEPRECATED config `elasticAPM.serverUrl`. Use env var: ELASTIC_APM_SERVER_URL'
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
if (isDefined(secretToken)) {
|
|
42
|
+
logger.notice(
|
|
43
|
+
'DEPRECATED config `elasticAPM.secretToken`. Use env var: ELASTIC_APM_SECRET_TOKEN'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// eslint-disable-next-line no-process-env
|
|
48
|
+
config.elasticAPM.active = isActive(config.elasticAPM, process.env);
|
|
49
|
+
|
|
50
|
+
return { ...config };
|
|
51
|
+
};
|
package/lib/cookies.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Returns an array of cookie names which are considered sensitive because they
|
|
3
3
|
* may contain session credential or PII
|
|
4
|
-
*
|
|
5
|
-
* @param {*} config the Gasket config object
|
|
4
|
+
* @param {import('@gasket/engine').GasketConfig} config the Gasket config
|
|
6
5
|
* @returns {string[]} an array of cookie names
|
|
7
6
|
*/
|
|
8
7
|
const sensitiveCookies = (config) => {
|
|
@@ -18,28 +17,30 @@ const sensitiveCookies = (config) => {
|
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
19
|
* Redacts the contents of user-specified sensitive cookies
|
|
21
|
-
*
|
|
22
|
-
* @param {object} config The Gasket config
|
|
23
|
-
* @param {object} payload The APM payload
|
|
24
|
-
* @returns {object} a modified version of the incoming APM payload
|
|
20
|
+
* @type {import('./index').filterSensitiveCookies}
|
|
25
21
|
*/
|
|
26
|
-
const filterSensitiveCookies = (config)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
const filterSensitiveCookies = function (config) {
|
|
23
|
+
return function (payload) {
|
|
24
|
+
if (
|
|
25
|
+
payload.context &&
|
|
26
|
+
payload.context.request &&
|
|
27
|
+
payload.context.request.headers &&
|
|
28
|
+
payload.context.request.headers.cookie
|
|
29
|
+
) {
|
|
30
|
+
let cookie = payload.context.request.headers.cookie;
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
sensitiveCookies(config).forEach((sc) => {
|
|
33
|
+
cookie = cookie.replace(
|
|
34
|
+
new RegExp(sc + '=([^;]+)'),
|
|
35
|
+
sc + '=[REDACTED]'
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
payload.context.request.headers.cookie = cookie;
|
|
40
|
+
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
return payload;
|
|
43
|
+
};
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
module.exports = {
|
package/lib/index.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'http';
|
|
2
|
-
import type { Agent, AgentConfigOptions, Transaction } from 'elastic-apm-node';
|
|
3
|
-
import type { MaybeAsync } from '@gasket/engine';
|
|
2
|
+
import type { Agent, AgentConfigOptions, Transaction, Payload } from 'elastic-apm-node';
|
|
3
|
+
import type { MaybeAsync, GasketConfig } from '@gasket/engine';
|
|
4
|
+
import type { GasketData } from '@gasket/data';
|
|
5
|
+
|
|
6
|
+
export function filterSensitiveCookies(config: GasketConfig): function(Payload): Payload;
|
|
7
|
+
|
|
8
|
+
interface ExtendedAgentConfigOptions extends AgentConfigOptions {
|
|
9
|
+
sensitiveCookies?: Array<string>;
|
|
10
|
+
}
|
|
4
11
|
|
|
5
12
|
declare module '@gasket/engine' {
|
|
6
13
|
export interface GasketConfig {
|
|
7
|
-
elasticAPM?:
|
|
8
|
-
sensitiveCookies?: Array<string>
|
|
9
|
-
},
|
|
14
|
+
elasticAPM?: ExtendedAgentConfigOptions;
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
export interface Gasket {
|
|
@@ -17,9 +22,15 @@ declare module '@gasket/engine' {
|
|
|
17
22
|
apmTransaction(
|
|
18
23
|
transaction: Transaction,
|
|
19
24
|
details: {
|
|
20
|
-
req: IncomingMessage
|
|
21
|
-
res: ServerResponse
|
|
25
|
+
req: IncomingMessage;
|
|
26
|
+
res: ServerResponse & {
|
|
27
|
+
locals?: {
|
|
28
|
+
gasketData: GasketData & {
|
|
29
|
+
locale?: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
22
33
|
}
|
|
23
|
-
): MaybeAsync<void
|
|
34
|
+
): MaybeAsync<void>;
|
|
24
35
|
}
|
|
25
36
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,78 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { dependencies } = require('../package.json');
|
|
4
|
-
|
|
5
|
-
const isDefined = o => typeof o !== 'undefined';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Determines if the Elastic APM agent has sufficient config to be active
|
|
9
|
-
* @param {object} config gasket config
|
|
10
|
-
* @param {object<string,any>} env environment variables
|
|
11
|
-
* @returns {boolean} A combined config object
|
|
12
|
-
*/
|
|
13
|
-
const isActive = (config, env) => {
|
|
14
|
-
const { active, serverUrl, secretToken } = config;
|
|
15
|
-
|
|
16
|
-
if (active || env.ELASTIC_APM_ACTIVE) {
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const combined = {
|
|
21
|
-
serverUrl: serverUrl || env.ELASTIC_APM_SERVER_URL,
|
|
22
|
-
secretToken: secretToken || env.ELASTIC_APM_SECRET_TOKEN
|
|
23
|
-
};
|
|
1
|
+
/// <reference types="@gasket/cli" />
|
|
2
|
+
/// <reference types="@gasket/plugin-metadata" />
|
|
24
3
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return false;
|
|
30
|
-
};
|
|
4
|
+
const middleware = require('./middleware');
|
|
5
|
+
const preboot = require('./preboot');
|
|
6
|
+
const configure = require('./configure');
|
|
7
|
+
const { dependencies, name } = require('../package.json');
|
|
31
8
|
|
|
32
|
-
|
|
9
|
+
/** @type {import('@gasket/engine').Plugin} */
|
|
10
|
+
const plugin = {
|
|
11
|
+
name,
|
|
33
12
|
hooks: {
|
|
34
|
-
configure
|
|
35
|
-
|
|
36
|
-
const { logger } = gasket;
|
|
37
|
-
config.elasticAPM = config.elasticAPM || {};
|
|
38
|
-
|
|
39
|
-
const { serverUrl, secretToken } = config.elasticAPM;
|
|
40
|
-
if (isDefined(serverUrl)) {
|
|
41
|
-
logger.notice('DEPRECATED config `elasticAPM.serverUrl`. Use env var: ELASTIC_APM_SERVER_URL');
|
|
42
|
-
}
|
|
43
|
-
if (isDefined(secretToken)) {
|
|
44
|
-
logger.notice('DEPRECATED config `elasticAPM.secretToken`. Use env var: ELASTIC_APM_SECRET_TOKEN');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// eslint-disable-next-line no-process-env
|
|
48
|
-
config.elasticAPM.active = isActive(config.elasticAPM, process.env);
|
|
49
|
-
|
|
50
|
-
return { ...config };
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
preboot: {
|
|
54
|
-
handler: async (gasket) => {
|
|
55
|
-
const { config, logger, command } = gasket;
|
|
56
|
-
|
|
57
|
-
if (command && command.id === 'local') return;
|
|
58
|
-
|
|
59
|
-
// prefer app-level dependency in case of duplicates
|
|
60
|
-
const apm = require(
|
|
61
|
-
require.resolve('elastic-apm-node', { paths: [config.root, __dirname] })
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
if (!apm.isStarted()) {
|
|
65
|
-
apm.start({
|
|
66
|
-
...config.elasticAPM
|
|
67
|
-
});
|
|
68
|
-
logger.notice('DEPRECATED started Elastic APM agent late. Use `--require elastic-apm-node/start`');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
apm.addFilter(filterSensitiveCookies(config));
|
|
72
|
-
|
|
73
|
-
gasket.apm = apm;
|
|
74
|
-
}
|
|
75
|
-
},
|
|
13
|
+
configure,
|
|
14
|
+
preboot,
|
|
76
15
|
create: {
|
|
77
16
|
timing: {
|
|
78
17
|
after: ['@gasket/plugin-start']
|
|
@@ -90,26 +29,33 @@ module.exports = {
|
|
|
90
29
|
metadata(gasket, meta) {
|
|
91
30
|
return {
|
|
92
31
|
...meta,
|
|
93
|
-
configurations: [
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
32
|
+
configurations: [
|
|
33
|
+
{
|
|
34
|
+
name: 'elasticAPM',
|
|
35
|
+
link: 'README.md#configuration',
|
|
36
|
+
description: 'Configuration to provide additional setup helpers',
|
|
37
|
+
type: 'object'
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'elasticAPM.sensitiveCookies',
|
|
41
|
+
link: 'README.md#configuration',
|
|
42
|
+
description: 'List of sensitive cookies to filter',
|
|
43
|
+
type: 'string[]',
|
|
44
|
+
default: '[]'
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
lifecycles: [
|
|
48
|
+
{
|
|
49
|
+
name: 'apmTransaction',
|
|
50
|
+
method: 'exec',
|
|
51
|
+
description: 'Modify the APM transaction',
|
|
52
|
+
link: 'README.md#apmtransaction',
|
|
53
|
+
parent: 'middleware'
|
|
54
|
+
}
|
|
55
|
+
]
|
|
112
56
|
};
|
|
113
57
|
}
|
|
114
58
|
}
|
|
115
59
|
};
|
|
60
|
+
|
|
61
|
+
module.exports = plugin;
|
package/lib/middleware.js
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
// @ts-check
|
|
3
|
-
/// <reference types="./index" />
|
|
4
|
-
/// <reference types="../../gasket-plugin-nextjs" />
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @typedef {import('@gasket/engine').Gasket} Gasket
|
|
8
|
-
* @typedef {import('http').IncomingMessage} Request
|
|
9
|
-
* @typedef {import('http').ServerResponse} Response
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const { callbackify } = require('util');
|
|
1
|
+
/// <reference types="@gasket/plugin-express" />
|
|
13
2
|
|
|
14
3
|
/**
|
|
15
4
|
* Middleware for customizing transactions
|
|
16
|
-
*
|
|
17
|
-
* @param {
|
|
18
|
-
* @param {
|
|
19
|
-
* @param {Response} res The server response
|
|
5
|
+
* @param {import('@gasket/engine').Gasket} gasket - The Gasket engine
|
|
6
|
+
* @param {import('http').IncomingMessage} req - The HTTP request being handled
|
|
7
|
+
* @param {import('http').ServerResponse} res - The server response
|
|
20
8
|
*/
|
|
21
9
|
async function customizeTransaction(gasket, req, res) {
|
|
22
10
|
const apm = gasket.apm;
|
|
@@ -33,9 +21,20 @@ async function customizeTransaction(gasket, req, res) {
|
|
|
33
21
|
await gasket.exec('apmTransaction', transaction, { req, res });
|
|
34
22
|
}
|
|
35
23
|
|
|
36
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Add middleware to gather config details
|
|
26
|
+
* @type {import('@gasket/engine').HookHandler<'middleware'>}
|
|
27
|
+
*/
|
|
28
|
+
module.exports = function middleware(gasket) {
|
|
37
29
|
return (
|
|
38
|
-
gasket.apm
|
|
39
|
-
|
|
30
|
+
gasket.apm &&
|
|
31
|
+
async function apmTransactionMiddleware(req, res, next) {
|
|
32
|
+
try {
|
|
33
|
+
customizeTransaction(gasket, req, res);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return next(error);
|
|
36
|
+
}
|
|
37
|
+
next();
|
|
38
|
+
}
|
|
40
39
|
);
|
|
41
40
|
};
|
package/lib/preboot.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/// <reference types="@gasket/plugin-start" />
|
|
2
|
+
/// <reference types="@gasket/plugin-log" />
|
|
3
|
+
|
|
4
|
+
const { filterSensitiveCookies } = require('./cookies');
|
|
5
|
+
|
|
6
|
+
/** @type {import('@gasket/engine').HookHandler<'preboot'>} */
|
|
7
|
+
module.exports = async function preboot(gasket) {
|
|
8
|
+
const { config, logger, command } = gasket;
|
|
9
|
+
|
|
10
|
+
if (command && command.id === 'local') return;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @type {import('elastic-apm-node')}
|
|
14
|
+
* Note: Prefer app-level dependency in case of duplicates
|
|
15
|
+
*/
|
|
16
|
+
const apm = require(require.resolve('elastic-apm-node', {
|
|
17
|
+
paths: [config.root, __dirname]
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
if (!apm.isStarted()) {
|
|
21
|
+
apm.start({
|
|
22
|
+
...config.elasticAPM
|
|
23
|
+
});
|
|
24
|
+
logger.notice(
|
|
25
|
+
'DEPRECATED started Elastic APM agent late. Use `--require elastic-apm-node/start`'
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
apm.addFilter(filterSensitiveCookies(config));
|
|
30
|
+
|
|
31
|
+
gasket.apm = apm;
|
|
32
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gasket/plugin-elastic-apm",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.47.1",
|
|
4
4
|
"description": "Adds Elastic APM instrumentation to your application",
|
|
5
5
|
"main": "lib",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"test:runner": "jest test/*.test.js",
|
|
15
15
|
"test:watch": "npm run test:runner -- --watch",
|
|
16
16
|
"test:coverage": "npm run test:runner -- --coverage --coverageReporters text",
|
|
17
|
-
"posttest": "npm run lint",
|
|
17
|
+
"posttest": "npm run lint && npm run typecheck",
|
|
18
18
|
"report": "npm run test:runner -- --coverage --coverageReporters lcov",
|
|
19
|
-
"typecheck
|
|
19
|
+
"typecheck": "tsc",
|
|
20
20
|
"typecheck:watch": "tsc --watch"
|
|
21
21
|
},
|
|
22
22
|
"repository": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"elastic-apm-node": "^3.50.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@gasket/engine": "^6.
|
|
48
|
+
"@gasket/engine": "^6.47.1",
|
|
49
49
|
"eslint": "^8.56.0",
|
|
50
50
|
"eslint-config-godaddy": "^7.1.0",
|
|
51
51
|
"eslint-plugin-jest": "^27.6.3",
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"jest": {
|
|
73
73
|
"testEnvironment": "node"
|
|
74
74
|
},
|
|
75
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "9bf7fe135d46371e32afe289e69307d44574ff7c"
|
|
76
76
|
}
|