@contrast/agentify
Advanced tools
Comparing version 1.20.1 to 1.21.0
144
lib/index.js
@@ -22,2 +22,10 @@ /* | ||
const ERROR_MESSAGE = 'An error prevented the Contrast agent from installing. The application will be run without instrumentation.'; | ||
/** | ||
* Specific agents may want to add their startup validation to this list as needed. | ||
* We have to install the reporter first since installation is contingent on TS onboarding responses. | ||
* Otherwise, the order of installing side effects doesn't matter too much. Ideally, the installations | ||
* that most affect the environment and "normal" execution of things should be done lastly e.g. modifying prototypes. | ||
* A good rule might be to install in the order such that side-effects that are easier to undo should be done first. | ||
* With that rule in mind, ESM support is the most complex (loader agent) so it should come last. | ||
*/ | ||
const DEFAULT_INSTALL_ORDER = [ | ||
@@ -36,8 +44,13 @@ 'reporter', | ||
'heapSnapshots', | ||
'metrics', | ||
'rewriteHooks', | ||
'functionHooks', | ||
'metrics', | ||
'esmHooks', | ||
]; | ||
/** | ||
* Utility for making agents: entrypoints indended to be run via --require, --loader, --import. | ||
* Composes all needed dependencies during factory instantiation, and installs various components | ||
* that alter an application's environment in order for composed features to operate e.g. request scopes, | ||
* source code rewrite hooks etc. | ||
* @param {any} core | ||
@@ -47,2 +60,68 @@ * @returns {import('.').Agentify} | ||
module.exports = function init(core = {}) { | ||
let _callback; | ||
let _opts; | ||
core.agentify = async function agentify(callback, opts = {}) { | ||
_callback = callback; | ||
_opts = opts; | ||
_opts.type = _opts.type ?? 'cjs'; | ||
_opts.installOrder = _opts.installOrder ?? DEFAULT_INSTALL_ORDER; | ||
// for 'cjs' we hook runMain and install prior to running it | ||
if (_opts.type === 'cjs') { | ||
if (typeof callback !== 'function') { | ||
throw new Error('Invalid usage: first argument must be a function'); | ||
} | ||
const { runMain } = Module; | ||
/** | ||
* This is one side effect that will always occur, even with `installOrder: []`. | ||
* The act of calling `agentify()` is enough to cause this side effect, by design. | ||
*/ | ||
Module.runMain = async function (...args) { | ||
await install(); | ||
return runMain.apply(this, args); | ||
}; | ||
} else { | ||
// for 'esm' we load esm-hooks support, which will install lastly | ||
const { default: esmHooks } = await import('@contrast/esm-hooks/lib/index.mjs'); | ||
esmHooks(core); | ||
await install(); | ||
} | ||
return core; | ||
}; | ||
async function install() { | ||
const { config, logger } = core; | ||
try { | ||
for (const err of config._errors) { | ||
throw err; // move this into config itself since we now handle errors | ||
} | ||
logger.info('Starting %s v%s', core.agentName, core.agentVersion); | ||
logger.info({ config }, 'Agent configuration'); | ||
const plugin = await _callback?.(core); | ||
for (const svcName of _opts.installOrder ?? []) { | ||
const svc = core[svcName]; | ||
if (svc?.install) { | ||
logger.trace('installing service: %s', svcName); | ||
await svc.install(); | ||
} | ||
} | ||
if (plugin?.install) { | ||
await plugin.install(); | ||
} | ||
core.logDiagnosticFiles(); // should this be moved into a separate install side-effect? | ||
} catch (err) { | ||
// TODO: Consider proper UNINSTALLATION and normal startup w/o agent | ||
logger.error({ err }, ERROR_MESSAGE); | ||
} | ||
} | ||
try { | ||
@@ -55,4 +134,2 @@ require('@contrast/core/lib/messages')(core); | ||
require('@contrast/logger').default(core); | ||
// @contrast/info ? | ||
require('@contrast/core/lib/agent-info')(core); | ||
@@ -69,6 +146,4 @@ require('@contrast/core/lib/system-info')(core); | ||
require('@contrast/core/lib/capture-stacktrace')(core); | ||
require('@contrast/rewriter')(core); // merge contrast-methods? | ||
require('@contrast/core/lib/contrast-methods')(core); // can we remove dependency on patcher? | ||
require('@contrast/scopes')(core); | ||
@@ -80,3 +155,3 @@ require('@contrast/deadzones')(core); | ||
// compose add'l local services | ||
// compose additional local services | ||
require('./heap-snapshots')(core); | ||
@@ -87,57 +162,2 @@ require('./sources')(core); | ||
require('./rewrite-hooks')(core); | ||
/** | ||
* The interface is a function, which when called, will hook runMain | ||
* @type {import('.').Agentify} | ||
*/ | ||
core.agentify = function agentify( | ||
preRunMain, | ||
{ installOrder = DEFAULT_INSTALL_ORDER } = {}, | ||
) { | ||
if (typeof preRunMain !== 'function') { | ||
throw new Error('Invalid usage: first argument must be a function'); | ||
} | ||
const { runMain } = Module; | ||
const { config, logger } = core; | ||
/** | ||
* This is one side effect that will always occur, even with `installOrder: []`. | ||
* The act of calling `agentify()` is enough to cause this side effect, by design. | ||
*/ | ||
Module.runMain = async function (...args) { | ||
try { | ||
for (const err of config._errors) { | ||
throw err; // move this into config itself since we now handle errors | ||
} | ||
logger.info('Starting %s v%s', core.agentName, core.agentVersion); | ||
// pino serializers know how to log redacted values and omit certain props | ||
logger.info({ config }, 'Agent configuration'); | ||
const plugin = await preRunMain(core); | ||
for (const svcName of installOrder ?? []) { | ||
const svc = core[svcName]; | ||
if (svc?.install) { | ||
logger.trace('installing service: %s', svcName); | ||
await svc.install(); | ||
} | ||
} | ||
if (plugin?.install) { | ||
await plugin.install(); | ||
} | ||
core.logDiagnosticFiles(); // should this be moved into a separate install side-effect? | ||
} catch (err) { | ||
// TODO: Consider proper UNINSTALLATION and normal startup w/o agent | ||
logger.error({ err }, ERROR_MESSAGE); | ||
} | ||
return runMain.apply(this, args); | ||
}; | ||
return core; | ||
}; | ||
} catch (err) { | ||
@@ -161,1 +181,3 @@ // TODO: Consider proper UNINSTALLATION and normal startup w/o agent | ||
}; | ||
module.exports.DEFAULT_INSTALL_ORDER = DEFAULT_INSTALL_ORDER; |
@@ -47,4 +47,2 @@ /* | ||
}; | ||
// if threadInfo is present, this is running with --loader or --import | ||
core.threadInfo?.post('rewrite', options); | ||
@@ -51,0 +49,0 @@ const { code } = core.rewriter.rewrite(content, options); |
{ | ||
"name": "@contrast/agentify", | ||
"version": "1.20.1", | ||
"version": "1.21.0", | ||
"description": "Configures Contrast agent services and instrumentation within an application", | ||
@@ -20,13 +20,13 @@ "license": "SEE LICENSE IN LICENSE", | ||
"dependencies": { | ||
"@contrast/common": "1.18.0", | ||
"@contrast/config": "1.25.0", | ||
"@contrast/core": "1.29.1", | ||
"@contrast/common": "1.19.0", | ||
"@contrast/config": "1.26.0", | ||
"@contrast/core": "1.30.0", | ||
"@contrast/deadzones": "1.1.2", | ||
"@contrast/dep-hooks": "1.3.1", | ||
"@contrast/esm-hooks": "2.2.1", | ||
"@contrast/instrumentation": "1.5.0", | ||
"@contrast/logger": "1.7.2", | ||
"@contrast/metrics": "1.4.0", | ||
"@contrast/esm-hooks": "2.3.0", | ||
"@contrast/instrumentation": "1.6.0", | ||
"@contrast/logger": "1.8.0", | ||
"@contrast/metrics": "1.5.0", | ||
"@contrast/patcher": "1.7.1", | ||
"@contrast/reporter": "1.24.0", | ||
"@contrast/reporter": "1.25.0", | ||
"@contrast/rewriter": "1.4.2", | ||
@@ -33,0 +33,0 @@ "@contrast/scopes": "1.4.0" |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
21841
10
526
+ Added@contrast/common@1.19.0(transitive)
+ Added@contrast/config@1.26.0(transitive)
+ Added@contrast/core@1.30.0(transitive)
+ Added@contrast/esm-hooks@2.3.0(transitive)
+ Added@contrast/instrumentation@1.6.0(transitive)
+ Added@contrast/logger@1.8.0(transitive)
+ Added@contrast/metrics@1.5.0(transitive)
+ Added@contrast/reporter@1.25.0(transitive)
- Removed@contrast/common@1.18.0(transitive)
- Removed@contrast/config@1.25.0(transitive)
- Removed@contrast/core@1.29.1(transitive)
- Removed@contrast/esm-hooks@2.2.1(transitive)
- Removed@contrast/instrumentation@1.5.0(transitive)
- Removed@contrast/logger@1.7.2(transitive)
- Removed@contrast/metrics@1.4.0(transitive)
- Removed@contrast/reporter@1.24.0(transitive)
Updated@contrast/common@1.19.0
Updated@contrast/config@1.26.0
Updated@contrast/core@1.30.0
Updated@contrast/esm-hooks@2.3.0
Updated@contrast/logger@1.8.0
Updated@contrast/metrics@1.5.0
Updated@contrast/reporter@1.25.0