Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

newrelic

Package Overview
Dependencies
Maintainers
1
Versions
383
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

newrelic - npm Package Compare versions

Comparing version 0.9.7-75 to 0.9.9-82

test/integration/versioned/express2-ejs/newrelic.js

12

index.js

@@ -15,3 +15,3 @@ 'use strict';

/**
/*
* Don't set up the rest of the agent if it didn't successfully load its

@@ -21,3 +21,11 @@ * configuration.

if (agent.config) {
// set up all of the instrumentation
/*
* In order to ensure all user code is using instrumented versions of
* modules, instrumentation must be loaded at startup regardless of
* whether or not the agent is enabled in the config. It should be
* possible for users to switch the agent on and off at runtime.
*
* This also requires the agent to be a singleton, or else module loading
* will be patched multiple times, with undefined results.
*/
shimmer.patchModule(agent);

@@ -24,0 +32,0 @@ shimmer.bootstrapInstrumentation(agent);

19

lib/agent.js

@@ -10,3 +10,3 @@ 'use strict';

, Context = require(path.join(__dirname, 'context'))
, ErrorService = require(path.join(__dirname, 'error'))
, ErrorTracer = require(path.join(__dirname, 'error'))
, Metrics = require(path.join(__dirname, 'metrics'))

@@ -41,3 +41,8 @@ , MetricNormalizer = require(path.join(__dirname, 'metrics', 'normalizer'))

this.config.on('change', this.updateApdexThreshold.bind(this));
logger.level(this.config.log_level || 'info');
/* older versions of the agent configured log level via log_level, but wanted a
* standard stanza to specify logfile location
*/
logger.level((this.config.logging && this.config.logging.level) ||
this.config.log_level ||
'info');

@@ -48,3 +53,3 @@ this.environment = require(path.join(__dirname, 'environment'));

// error tracing
this.errors = new ErrorService(this.config);
this.errors = new ErrorTracer(this.config);

@@ -73,3 +78,5 @@ // metrics

* managed by index.js. An agent will be created even if the agent's disabled by
* the configuration. There's probably a better way to do this.
* the configuration.
*
* @config agent_enabled (true|false) Whether to start up the agent.
*/

@@ -83,3 +90,3 @@ Agent.prototype.start = function () {

this.harvestIntervalId = setInterval(this.harvest.bind(this), 60 * 1000);
this.harvesterHandle = setInterval(this.harvest.bind(this), 60 * 1000);
sampler.start(this);

@@ -101,3 +108,3 @@

// stop the harvester coroutine
if (this.harvestIntervalId) clearInterval(this.harvestIntervalId);
if (this.harvesterHandle) clearInterval(this.harvesterHandle);

@@ -104,0 +111,0 @@ // shut down the sampler (and its own coroutines)

@@ -0,19 +1,116 @@

/**
* This file includes all of the configuration variables used by the Node.js
* agent. If there's a configurable element of the agent and it's not described
* in here, there's been a terrible mistake.
*/
exports.config = {
app_name : ['MyApplication'],
host : 'collector.newrelic.com',
port : 80,
log_level : 'info',
agent_enabled : true,
error_collector : {
enabled : true,
/**
* Array of application names.
*
* @env NR_APP_NAME
*/
app_name : ['MyApplication'],
/**
* The user's license key. Must be set by per-app configuration file.
*
* @env NR_LICENSE_KEY
*/
license_key : '',
/**
* Hostname for the New Relic collector proxy.
*
* You shouldn't need to change this.
*
* @env NR_COLLECTOR_HOST
*/
host : 'collector.newrelic.com',
/**
* The port on which the collector proxy will be listening.
*
* You shouldn't need to change this.
*
* @env NR_COLLECTOR_PORT
*/
port : 80,
logging : {
/**
* Verbosity of the agent logs. The agent uses bunyan
* (https://github.com/trentm/node-bunyan) for its logging, and as such
* the valid logging levels are 'fatal', 'error', 'warn', 'info', 'debug'
* and 'trace'. Logging at levels 'info' and higher is very terse. For
* support requests, attaching logs captured at 'trace' level are extremely
* helpful in chasing down bugs.
*
* @env NR_LOGGING_LEVEL
*/
level : 'info',
/**
* Where to put the log file -- by default just uses process.cwd +
* 'newrelic_agent.log'.
*
* @env NR_LOGGING_FILEPATH
*/
filepath : ''
},
/**
* Whether the agent is enabled.
*
* @env NR_AGENT_ENABLED
*/
agent_enabled : true,
/**
* Whether to collect & submit error traces to New Relic.
*
* @env NR_ERROR_COLLECTOR_ENABLED
*/
error_collector : {
enabled : true,
/**
* List of HTTP error status codes the error tracer should disregard.
* Defaults to 404 NOT FOUND.
*
* @env NR_ERROR_COLLECTOR_IGNORE_STATUS_CODES
*/
ignore_status_codes : [404]
},
transaction_tracer : {
enabled : true,
/**
* Whether to collect & submit slow transaction traces to New Relic.
*
* @env NR_TRANSACTION_TRACER_ENABLED
*/
enabled : true,
/**
* The duration at below which the slow transaction tracer should collect a
* transaction trace. If set to 'apdex_f', the threshold will be set to
* 4 * apdex_t, which with a default apdex_t value of 500 milliseconds will
* be 2000 milliseconds.
*
* If a time is provided, it is set in milliseconds.
*
* @env NR_TRANSACTION_TRACER_TRACE_THRESHOLD
*/
trace_threshold : 'apdex_f'
},
debug : {
/**
* Whether to enable internal supportability metrics and diagnostics. You're
* welcome to turn these on, but they will probably be most useful to the
* New Relic node engineering team.
*/
debug : {
/**
* Whether to collect and submit internal supportability metrics alongside
* application performance metrics.
*
* @env NR_DEBUG_INTERNAL_METRICS
*/
internal_metrics : false,
tracer_tracing : false
/**
* Traces the execution of the transaction tracer. Requires logging.level
* to be set to 'trace' to provide any useful output.
*
* @env NR_DEBUG_TRACER_TRACING
*/
tracer_tracing : false
}
};

@@ -10,45 +10,80 @@ 'use strict';

var DEFAULT_CONFIG = require(path.join(__dirname, 'config.default'));
/**
* CONSTANTS -- we gotta lotta 'em
*/
var DEFAULT_CONFIG = require(path.join(__dirname, 'config.default')).config;
function merge(defaults, config) {
Object.keys(defaults).forEach(function (name) {
if (config[name] !== undefined) {
if (Array.isArray(config[name])) {
// use the value in config
}
else if (typeof(defaults[name]) === 'object') {
merge(defaults[name], config[name]);
}
// else use the value in config
}
else {
config[name] = defaults[name];
}
});
}
/*
* ENV_MAPPING, LIST_VARS, and BOOLEAN_VARS could probably be unified and
* objectified, but this is simple and works.
*/
var ENV_MAPPING = {
newrelic_home : "NEWRELIC_HOME",
app_name : "NR_APP_NAME",
license_key : "NR_LICENSE_KEY",
host : "NR_COLLECTOR_HOST",
port : "NR_COLLECTOR_PORT",
logging : {
level : "NR_LOGGING_LEVEL",
filepath : "NR_LOGGING_FILEPATH"
},
agent_enabled : "NR_AGENT_ENABLED",
error_collector : {
enabled : "NR_ERROR_COLLECTOR_ENABLED",
ignore_status_codes : "NR_ERROR_COLLECTOR_IGNORE_STATUS_CODES"
},
transaction_tracer : {
enabled : "NR_TRANSACTION_TRACER_ENABLED",
trace_threshold : "NR_TRANSACTION_TRACER_TRACE_THRESHOLD"
},
debug : {
internal_metrics : "NR_DEBUG_INTERNAL_METRICS",
tracer_tracing : "NR_DEBUG_TRACER_TRACING"
}
};
function setDefaults(config) {
merge(DEFAULT_CONFIG, config);
}
// values in list variables are comma-delimited lists
var LIST_VARS = [
"NR_APP_NAME",
"NR_ERROR_COLLECTOR_IGNORE_STATUS_CODES"
];
function parseVersion() {
var text = fs.readFileSync(path.join(__dirname, '..', 'package.json'));
var json = JSON.parse(text);
/*
* Values in boolean variables. Is pretty tolerant about values, but
* don't get fancy and just use 'true' and 'false', everybody.
*/
var BOOLEAN_VARS = [
"NR_AGENT_ENABLED",
"NR_ERROR_COLLECTOR_ENABLED",
"NR_TRANSACTION_TRACER_ENABLED",
"NR_DEBUG_INTERNAL_METRICS",
"NR_DEBUG_TRACER_TRACING"
];
return json.version;
}
function Config(config) {
EventEmitter.call(this);
for (var name in config) if (config.hasOwnProperty(name)) this[name] = config[name];
// 1. start by cloning the defaults
var basis = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
Object.keys(basis).forEach(function (key) {
this[key] = basis[key];
}.bind(this));
this.version = parseVersion();
// 2. override defaults with values from the loaded / passed configuration
this._fromPassed(config);
// 3. override config with environment variables
this._fromEnvironment();
if (this.debug.internal_metrics) {
this.debug.supportability = new Metrics(this.apdex_t);
}
this.version = require(path.join(__dirname, '..', 'package.json')).version;
}
util.inherits(Config, EventEmitter);
/**
* Accept any configuration passed back from the server.
*/
Config.prototype.onConnect = function (params) {

@@ -60,2 +95,5 @@ this.apdex_t = params.apdex_t;

/**
* Ensure that the apps names are always returned as a list.
*/
Config.prototype.applications = function () {

@@ -72,2 +110,83 @@ var apps = this.app_name;

/**
* Safely overwrite defaults with values passed to constructor.
*
* @param object external The configuration being loaded.
* @param object internal Whichever chunk of the config being overrridden.
*/
Config.prototype._fromPassed = function (external, internal) {
if (!external) return;
if (!internal) internal = this;
Object.keys(external).forEach(function (key) {
var node = external[key];
if (typeof node === 'object') {
// if it's not in the defaults, it doesn't exist
if (!internal[key]) return;
this._fromPassed(node, internal[key]);
}
else {
internal[key] = node;
}
}.bind(this));
};
/**
* Recursively visit the nodes of the constant containing the mapping between
* environment variable names, overriding any configuration values that are
* found from the environment. Operates purely via side effects.
*
* @param object metadata The current level of the mapping object. Should never
* need to set this yourself.
* @param object data The current level of the configuration object. Should
* never need to set this yourself.
*/
Config.prototype._fromEnvironment = function (metadata, data) {
if (!metadata) metadata = ENV_MAPPING;
if (!data) data = this;
Object.keys(metadata).forEach(function (value) {
var node = metadata[value];
if (typeof node === 'string') {
var setting = process.env[node];
if (setting) {
if (LIST_VARS.indexOf(node) > -1) {
data[value] = setting.split(',');
}
else if (BOOLEAN_VARS.indexOf(node) > -1) {
var normalized = setting.toString().toLowerCase();
switch (normalized) {
case 'false':
case 'f':
case 'no':
case 'n':
case 'disabled':
case '0':
data[value] = false;
break;
default:
data[value] = true;
}
}
else {
data[value] = setting;
}
}
}
else {
// don't crash if the mapping has config keys the current config doesn't.
if (!data[value]) data[value] = {};
this._fromEnvironment(node, data[value]);
}
}.bind(this));
};
/**
* The agent will use the supportability metrics object if it's
* available.
*
* @param string suffix Supportability metric name.
* @param number duration Milliseconds that the measured operation took.
*/
Config.prototype.measureInternal = function (suffix, duration) {

@@ -81,4 +200,11 @@ if (this.debug.supportability) {

/**
* Create a configuration, either looking in the current working directory
* or in the directory specified by the environment variable NEWRELIC_HOME.
*
* @param object logger A logger following the standard logging API.
* @param object c Optional configuration to be used in place of a config file.
*/
function initialize(logger, c) {
var nrHome = process.env.NEWRELIC_HOME
var NEWRELIC_HOME = process.env.NEWRELIC_HOME
, DEFAULT_FILENAME = 'newrelic.js'

@@ -88,8 +214,13 @@ , config

if (typeof(c) === 'object') {
if (c && c.config) {
config = c;
}
else {
var filepath = path.join(process.cwd(), DEFAULT_FILENAME);
if (nrHome) filepath = path.join(nrHome, DEFAULT_FILENAME);
var filepath;
if (NEWRELIC_HOME) {
filepath = path.join(NEWRELIC_HOME, DEFAULT_FILENAME);
}
else {
filepath = path.join(process.cwd(), DEFAULT_FILENAME);
}

@@ -102,3 +233,4 @@ try {

"'. A default configuration file can be copied from '" +
path.join(__dirname, 'config.default.js') + "' and renamed to 'newrelic.js' " +
path.join(__dirname, 'config.default.js') +
"' and renamed to 'newrelic.js' " +
"in the directory from which you'll be running your app.");

@@ -110,10 +242,11 @@ }

setDefaults(config);
return new Config(config.config);
}
config = config.config;
if (nrHome) config.newrelic_home = nrHome;
/**
* Preserve the legacy initializer, but also allow consumers to manage their
* own configuration if they choose.
*/
Config.initialize = initialize;
return new Config(config);
}
exports.initialize = initialize;
module.exports = Config;
'use strict';
var path = require('path')
, logger = require(path.join(__dirname, 'logger')).child({component : 'error_service'})
, logger = require(path.join(__dirname, 'logger')).child({component : 'error_tracer'})
;

@@ -9,4 +9,16 @@

/**
* Given either or both of a transaction and an exception, generate an error
* trace in the JSON format expected by the collector. Since this will be
* used by both the HTTP instrumentation, which uses HTTP status codes to
* determine whether a transaction is in error, and the domain-based error
* handler, which traps actual instances of Error, try to set sensible
* defaults for everything.
*
* @param Transaction transaction The agent transaction, presumably coming out
* of the instrumentation.
* @param Error exception Something trapped by an error listener.
*/
function createError(transaction, exception) {
// the collector throws this out
// the collector throws this out, so don't bother setting it
var timestamp = 0;

@@ -44,10 +56,20 @@

function ErrorService(config) {
/**
* This is a fairly simple-minded tracer that converts errored-out HTTP
* transactions and JS Errors into the error traces expected by the collector.
*
* It also acts as a collector for the traced errors.
*/
function ErrorTracer(config) {
this.config = config;
this.errorCount = 0;
this.errors = [];
this.clear();
}
ErrorService.prototype.clear = function () {
/**
* (Re)Initialize the tracer.
*
* FIXME: for consistency's sake, it would be good to replace the error handler
* between request cycles.
*/
ErrorTracer.prototype.clear = function () {
this.errorCount = 0;

@@ -57,9 +79,13 @@ this.errors = [];

ErrorService.prototype.ignoreStatusCode = function (code) {
var codes = this.config.error_collector.ignore_status_codes;
ErrorTracer.prototype.ignoreStatusCode = function (code) {
var codes = this.config.error_collector.ignore_status_codes || [];
return codes.indexOf(code) !== -1;
};
ErrorService.prototype.onTransactionFinished = function (transaction) {
if (!transaction) throw new Error("Error service got a blank transaction.");
/**
* Every finished transaction goes through this handler, so do as
* little as possible.
*/
ErrorTracer.prototype.onTransactionFinished = function (transaction) {
if (!transaction) throw new Error("Error collector got a blank transaction.");

@@ -70,11 +96,27 @@ var code = transaction.statusCode;

ErrorService.prototype.add = function (transaction, exception) {
ErrorTracer.prototype.add = function (transaction, exception) {
this.errorCount++;
// allow enabling & disabling the error tracer at runtime
if (this.config.error_collector && !this.config.error_collector.enabled) return;
if (exception) logger.trace(exception, "Got exception to trace:");
var error = createError(transaction, exception);
logger.trace("Adding error: %j", error);
if (this.errors.length < MAX_ERRORS) this.errors.push(error);
if (this.errors.length < MAX_ERRORS) {
logger.debug({error : error}, "Error to be sent to collector:");
this.errors.push(error);
}
else {
logger.debug("Already have %d errors to send to collector, not logging.",
MAX_ERRORS);
logger.trace({error : error}, "JSON error.");
}
};
ErrorService.prototype.onSendError = function (errors) {
/**
* If the connection to the collector fails, retain as many as will fit
* without overflowing the current error list.
*/
ErrorTracer.prototype.onSendError = function (errors) {
var len = Math.min(errors.length, MAX_ERRORS - this.errors.length);

@@ -87,2 +129,2 @@

module.exports = ErrorService;
module.exports = ErrorTracer;

@@ -16,2 +16,36 @@ 'use strict';

/*
* So we can get the logfile location, we need to duplicate some of the
* configurator's logic.
*/
var NEWRELIC_HOME = process.env.NEWRELIC_HOME
, DEFAULT_FILENAME = 'newrelic.js'
, configpath
, config
;
if (NEWRELIC_HOME) {
configpath = path.join(NEWRELIC_HOME, DEFAULT_FILENAME);
}
else {
configpath = path.join(process.cwd(), DEFAULT_FILENAME);
}
try {
config = require(configpath).config;
}
catch (e) {
console.error("Unable to load New Relic agent configuration to start logger:",
e.stack);
}
var filepath;
// default config is empty string, which is falsy
if (config && config.logging && config.logging.filepath) {
filepath = config.logging.filepath;
}
else {
filepath = path.join(process.cwd(), 'newrelic_agent.log');
}
var logger = new Logger({

@@ -22,3 +56,3 @@ name : 'newrelic',

name : 'file',
path : path.join(process.cwd(), 'newrelic_agent.log')
path : filepath
}]

@@ -25,0 +59,0 @@ });

@@ -115,2 +115,6 @@ 'use strict';

// keep instrumented up to date
var pos = instrumented.indexOf(wrapped);
if (pos !== -1) instrumented.splice(pos, 1);
if (!wrapped) return logger.debug("%s not defined, so not unwrapping.", fqmn);

@@ -117,0 +121,0 @@ if (!wrapped.__NR_unwrap) return logger.debug("%s isn't unwrappable.", fqmn);

@@ -0,8 +1,24 @@

/**
* New Relic agent configuration.
*
* See lib/config.defaults.js in the agent distribution for a more complete
* description of configuration variables and their potential values.
*/
exports.config = {
app_name : ['My Application'],
license_key : 'license key here',
log_level : 'trace',
transaction_tracer : {
enabled : true
/**
* Array of application names.
*/
app_name : ['My Application'],
/**
* Your New Relic license key.
*/
license_key : 'license key here',
logging : {
/**
* Level at which to log. 'trace' is most useful to New Relic when diagnosing
* issues with the agent, 'info' and higher will impose the least overhead on
* production applications.
*/
level : 'debug'
}
};

@@ -0,1 +1,9 @@

### v0.9.9-82 / beta-09 (2012-12-12):
* Can now configure the agent via environment variables. See README.md for
details.
* Can now configure the location of the agent log via either logging.filepath
in the configuration file, or NR_LOGGING_FILEPATH in the app's environment.
* Turning off the error tracer via configuration now actually disables it.
### v0.9.7-75 / beta-08 (2012-12-06):

@@ -2,0 +10,0 @@

{
"name": "newrelic",
"version": "0.9.7-75",
"version": "0.9.9-82",
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",

@@ -5,0 +5,0 @@ "contributors": [

@@ -24,2 +24,6 @@ # New Relic Node.js agent

If you wish to keep the configuration for the agent separate from your
application, the agent will look for newrelic.js in the directory referenced
by the environment variable `NEWRELIC_HOME` if it's set.
When you start your app, the agent should start up with it and start reporting

@@ -35,2 +39,54 @@ data that will appear within our UI after a few minutes. Because the agent

## Configuring the agent
The agent can be tailored to your app's requirements, both from the server and
via the newrelic.js configuration file you created above. For more details on
what can be configured, refer to `lib/config.default.js`, which documents
the available variables and their default values.
In addition, for those of you running in Heroku, Microsoft Azure or any other
PaaS environment that makes it easier to control configuration via the your
server's environment, all of the configuration variables in newrelic.js have
counterparts that can be set in your service's shell environment. You can
mix and match the configuration file and environment variables freely; the
value found from the environment will always take precedence.
This documentation will be moving to New Relic's servers with the 1.0 release,
but for now, here's a list of the variables and their values:
* `NEWRELIC_HOME`: path to the director in which you've placed newrelic.js.
* `NR_APP_NAME`: The name of this application, for reporting to New Relic's
servers. This value can be also be a comma-delimited list of names.
* `NR_AGENT_ENABLED`: Whether or not the agent should run. Good for
temporarily disabling the agent while debugging other issues with your
code.
* `NR_LICENSE_KEY`: Your New Relic license key.
* `NR_LOGGING_LEVEL`: Logging priority for the New Relic agent. Can be one of
`error`, `warn`, `info`, `debug`, or `trace`. `debug` and `trace` are
pretty chatty; unless you're helping New Relic figure out irregularities
with the agent, you're probably best off using `info` or higher.
* `NR_LOGGING_FILEPATH`: Complete path to the New Relic agent log, including
the filename. The agent will shut down the process if it can't create
this file, and it creates the log file with the same umask of the
process.
* `NR_ERROR_COLLECTOR_ENABLED`: Whether or not to trace errors within your
application. Values are `true` or `false`.
* `NR_ERROR_COLLECTOR_IGNORE_STATUS_CODES`: Comma-delimited list of HTTP
status codes to ignore. Maybe you don't care if payment is required?
* `NR_TRANSACTION_TRACER_ENABLED`: Whether to collect and submit slow
transaction traces to New Relic. Values are `true` or `false`.
* `NR_TRANSACTION_TRACER_TRACE_THRESHOLD`: Millisecond duration at which
a transaction trace will count as slow and be sent to New Relic. Can
also be set to `apdex_f`, at which point it will set the trace threshold
to 4 times the current ApdexT.
* `NR_COLLECTOR_HOST`: Hostname for the New Relic collector proxy. You
shouldn't need to change this.
* `NR_COLLECTOR_PORT`: Port number on which the New Relic collector proxy
will be listening.
* `NR_DEBUG_INTERNAL_METRICS`: Whether to collect internal supportability
metrics for the agent. Don't mess with this unless New Relic asks you to.
* `NR_DEBUG_TRACER_TRACING`: Whether to dump traces of the transaction tracer's
internal operation. You're welcome to enable it, but it's unlikely to be
edifying unless you're a New Relic Node.js engineer.
## Running tests

@@ -37,0 +93,0 @@

@@ -13,10 +13,179 @@ 'use strict';

function idempotentEnv(name, value, callback) {
var is, saved;
// process.env is not a normal object
if (Object.hasOwnProperty.call(process.env, name)) {
is = true;
saved = process.env[name];
}
process.env[name] = value;
try {
var tc = config.initialize(logger);
callback(tc);
}
catch (error) {
throw error;
}
finally {
if (is) {
process.env[name] = saved;
}
else {
delete process.env[name];
}
}
}
describe("the agent configuration", function () {
it("should handle a directly passed minimal configuration", function (done) {
it("should handle a directly passed minimal configuration", function () {
var c = config.initialize(logger, {config : {'agent_enabled' : false}});
c.agent_enabled.should.equal(false);
});
return done();
describe("when overriding configuration values via environment variables", function () {
it("should pick up the application name", function () {
idempotentEnv('NR_APP_NAME', 'feeling testy,and schizophrenic', function (tc) {
should.exist(tc.app_name);
expect(tc.app_name).eql(['feeling testy', 'and schizophrenic']);
});
});
it("should pick up the license key", function () {
idempotentEnv('NR_LICENSE_KEY', 'hambulance', function (tc) {
should.exist(tc.license_key);
expect(tc.license_key).equal('hambulance');
});
});
it("should pick up the collector host", function () {
idempotentEnv('NR_COLLECTOR_HOST', 'localhost', function (tc) {
should.exist(tc.host);
expect(tc.host).equal('localhost');
});
});
it("should pick up the collector port", function () {
idempotentEnv('NR_COLLECTOR_PORT', 7777, function (tc) {
should.exist(tc.port);
expect(tc.port).equal('7777');
});
});
it("should pick up the log level", function () {
idempotentEnv('NR_LOGGING_LEVEL', 'XXNOEXIST', function (tc) {
should.exist(tc.logging.level);
expect(tc.logging.level).equal('XXNOEXIST');
});
});
it("should pick up the log filepath", function () {
idempotentEnv('NR_LOGGING_FILEPATH', '/highway/to/the/danger/zone', function (tc) {
should.exist(tc.logging.filepath);
expect(tc.logging.filepath).equal('/highway/to/the/danger/zone');
});
});
it("should pick up whether the agent is enabled", function () {
idempotentEnv('NR_AGENT_ENABLED', 0, function (tc) {
should.exist(tc.agent_enabled);
expect(tc.agent_enabled).equal(false);
});
});
it("should pick up whether the error collector is enabled", function () {
idempotentEnv('NR_ERROR_COLLECTOR_ENABLED', 'NO', function (tc) {
should.exist(tc.error_collector.enabled);
expect(tc.error_collector.enabled).equal(false);
});
});
it("should pick up which status codes are ignored", function () {
idempotentEnv('NR_ERROR_COLLECTOR_IGNORE_STATUS_CODES', '401,404,502', function (tc) {
should.exist(tc.error_collector.ignore_status_codes);
expect(tc.error_collector.ignore_status_codes).eql(['401', '404', '502']);
});
});
it("should pick up whether the transaction tracer is enabled", function () {
idempotentEnv('NR_TRANSACTION_TRACER_ENABLED', false, function (tc) {
should.exist(tc.transaction_tracer.enabled);
expect(tc.transaction_tracer.enabled).equal(false);
});
});
it("should pick up the transaction trace threshold", function () {
idempotentEnv('NR_TRANSACTION_TRACER_TRACE_THRESHOLD', 0.02, function (tc) {
should.exist(tc.transaction_tracer.trace_threshold);
expect(tc.transaction_tracer.trace_threshold).equal('0.02');
});
});
it("should pick up whether internal metrics are enabled", function () {
idempotentEnv('NR_DEBUG_INTERNAL_METRICS', true, function (tc) {
should.exist(tc.debug.internal_metrics);
expect(tc.debug.internal_metrics).equal(true);
});
});
it("should pick up whether tracing of the transaction tracer is enabled", function () {
idempotentEnv('NR_DEBUG_TRACER_TRACING', 'yup', function (tc) {
should.exist(tc.debug.tracer_tracing);
expect(tc.debug.tracer_tracing).equal(true);
});
});
});
describe("with default properties", function () {
var configuration;
before(function () {
configuration = config.initialize(logger, {config : {}});
// ensure environment is clean
delete configuration.newrelic_home;
});
it("should have an app name of ['MyApplication']", function () {
configuration.app_name.should.eql(['MyApplication']);
});
it("should connect to the collector at collector.newrelic.com", function () {
configuration.host.should.equal('collector.newrelic.com');
});
it("should connect to the collector on port 80", function () {
configuration.port.should.equal(80);
});
it("should log at the info level by default", function () {
configuration.logging.level.should.equal('info');
});
it("should have a blank default log filepath", function () {
configuration.logging.filepath.should.equal('');
});
it("should enable the agent by default", function () {
configuration.agent_enabled.should.equal(true);
});
it("should enable the error collector by default", function () {
configuration.error_collector.enabled.should.equal(true);
});
it("should ignore status code 404 by default", function () {
configuration.error_collector.ignore_status_codes.should.eql([404]);
});
it("should enable the transaction tracer by default", function () {
configuration.transaction_tracer.enabled.should.equal(true);
});
it("should set the transaction tracer threshold to 'apdex_f' by default", function () {
configuration.transaction_tracer.trace_threshold.should.equal('apdex_f');
});
});
describe("when overriding the config file location via NR_HOME", function () {

@@ -85,19 +254,3 @@ var origHome

});
it("should correctly expose all of the default properties", function () {
var configuration = config.initialize(logger);
delete configuration.newrelic_home;
configuration.app_name.should.eql(['MyApplication']);
configuration.host.should.equal('collector.newrelic.com');
configuration.port.should.equal(80);
configuration.log_level.should.equal('info');
configuration.agent_enabled.should.equal(true);
configuration.error_collector.enabled.should.equal(true);
configuration.error_collector.ignore_status_codes.should.eql([404]);
configuration.transaction_tracer.enabled.should.equal(true);
configuration.transaction_tracer.trace_threshold.should.equal('apdex_f');
});
});
});

@@ -12,3 +12,3 @@ 'use strict';

, DataSender = require(path.join(__dirname, '..', 'lib', 'collector', 'data-sender'))
, ErrorService = require(path.join(__dirname, '..', 'lib', 'error'))
, ErrorTracer = require(path.join(__dirname, '..', 'lib', 'error'))
, Metrics = require(path.join(__dirname, '..', 'lib', 'metrics'))

@@ -100,3 +100,3 @@ , SQLTrace = require(path.join(__dirname, '..', 'lib', 'transaction', 'trace', 'sql'))

it("should send traced errors in the expected format", function () {
var errors = new ErrorService(agent.config);
var errors = new ErrorTracer(agent.config);

@@ -103,0 +103,0 @@ var transaction = new Transaction(agent);

@@ -10,3 +10,3 @@ 'use strict';

, dominion = require(path.join(__dirname, '..', 'lib', 'dominion'))
, ErrorService = require(path.join(__dirname, '..', 'lib', 'error'))
, ErrorTracer = require(path.join(__dirname, '..', 'lib', 'error'))
, Transaction = require(path.join(__dirname, '..', 'lib', 'transaction'))

@@ -19,21 +19,36 @@ ;

describe("ErrorService", function () {
describe("ErrorTracer", function () {
var service;
beforeEach(function () {
service = new ErrorService(config.config);
service = new ErrorTracer(config.config);
});
it("should send the correct number of errors", function () {
var errors = [1, 2, 3, 4, 5];
it("shouldn't gather errors if it's switched off", function () {
var error = new Error('this error will never be seen');
service.config.error_collector.enabled = false;
service.onSendError(errors);
expect(service.errorCount).equal(0);
expect(service.errors.length).equal(0);
service.add(error);
expect(service.errorCount).equal(1);
expect(service.errors.length).equal(0);
service.config.error_collector.enabled = true;
});
it("should retain a maximum of 20 errors to send", function () {
var error = new Error('test error');
for (var i = 0; i < 5; i++) service.add(null, error);
expect(service.errors.length).equal(5);
service.onSendError(errors);
for (i = 0; i < 5; i++) service.add(null, error);
expect(service.errors.length).equal(10);
service.onSendError(errors);
service.onSendError(errors);
service.onSendError([3,4,5,6,6,6,6,6]); // we're over the max here.
// this will take the tracer 3 over the limit of 20
for (i = 0; i < 13; i++) service.add(null, error);
expect(service.errorCount).equal(23);
expect(service.errors.length).equal(20);

@@ -68,3 +83,3 @@ });

beforeEach(function () {
service = new ErrorService(config.config);
service = new ErrorTracer(config.config);

@@ -71,0 +86,0 @@ agent = helper.loadMockedAgent();

exports.config = {
app_name : ['My Application'],
license_key : 'license key here',
log_level : 'trace',
logging : {
level : 'trace',
filepath : '../../newrelic_agent.log'
},
transaction_tracer : {

@@ -6,0 +9,0 @@ enabled : true

@@ -60,4 +60,4 @@ 'use strict';

agent.stop();
shimmer.unpatchModule();
shimmer.unwrapAll();
shimmer.unpatchModule();
},

@@ -64,0 +64,0 @@

### KNOWN ISSUES:
* The CPU and memory overhead incurred by the Node agent is relatively
minor (~1-10%, depending on how much of the instrumentation your
apps end up using), but may not be appropriate for production use.
In particular, GC activity is significantly increased due to the
large number of ephemeral objects created by metrics gathering. For
now, be judicious about which production apps you install the agent in.
It may not be appropriate for latency-sensitive or high-throughput
applications.
minor (~1-10%, depending on how much of the instrumentation your
apps end up using), but may not be appropriate for production use.
In particular, GC activity is significantly increased due to the
large number of ephemeral objects created by metrics gathering. For
now, be judicious about which production apps you install the agent in.
It may not be appropriate for latency-sensitive or high-throughput
applications.
* There are irregularities around transaction trace capture and display.
If you notice missing or incorrect information from transaction traces,
let us know. If possible, include the package.json for your application
with your report.
If you notice missing or incorrect information from transaction traces,
let us know. If possible, include the package.json for your application
with your report.
* The agent works only with Node.js 0.6 and newer.
* Transaction and error tracing can't be disabled right now.
* When using Node's included clustering support, each worker process will
open its own connection to New Relic's servers, and will incur its own
overhead costs.
open its own connection to New Relic's servers, and will incur its own
overhead costs.

@@ -21,0 +20,0 @@ ### TO DO:

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc