New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

newrelic

Package Overview
Dependencies
Maintainers
1
Versions
394
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 1.9.2 to 1.10.0

lib/instrumentation/pg.js

35

api.js

@@ -8,5 +8,7 @@ 'use strict';

, recordWeb = require(path.join(__dirname, 'lib', 'metrics',
'recorders', 'http.js'))
, genericRecorder = require(path.join(__dirname, 'lib', 'metrics', 'recorders',
'generic'))
'recorders', 'http.js'))
, recordBackground = require(path.join(__dirname, 'lib', 'metrics',
'recorders', 'other.js'))
, customRecorder = require(path.join(__dirname, 'lib', 'metrics', 'recorders',
'custom'))
;

@@ -403,3 +405,3 @@

if (txn) {
var segment = tracer.addSegment(name, genericRecorder);
var segment = tracer.addSegment(name, customRecorder);
return tracer.callbackProxy(function () {

@@ -422,4 +424,5 @@ callback.apply(this, arguments);

return tracer.transactionNestProxy(tracer.segmentProxy(function(){
return tracer.transactionNestProxy('web', tracer.segmentProxy(function(){
var tx = tracer.getTransaction();
tx.partialName = NAMES.CUSTOM + NAMES.ACTION_DELIMITER + url;
tx.setName(url, 0);

@@ -432,2 +435,24 @@ tx.webSegment = tracer.addSegment(url, recordWeb);

API.prototype.createBackgroundTransaction = function createBackgroundTransaction(name, group, callback) {
if (callback === undefined && typeof group === 'function') {
callback = group;
group = 'Nodejs';
}
// FLAG: custom_instrumentation
if (!this.agent.config.feature_flag.custom_instrumentation) {
return callback;
}
var tracer = this.agent.tracer;
return tracer.transactionNestProxy('bg', tracer.segmentProxy(function(){
var tx = tracer.getTransaction();
tx.setBackgroundName(name, group);
tx.bgSegment = tracer.addSegment(name, recordBackground);
tx.bgSegment.partialName = group;
callback.apply(this, arguments);
}));
};
API.prototype.endTransaction = function endTransaction() {

@@ -434,0 +459,0 @@ // FLAG: custom_instrumentation

@@ -11,3 +11,6 @@ 'use strict';

var agentVersion = require(path.join(__dirname, 'package.json')).version;
logger.trace("Using New Relic for Node.js version %s.", agentVersion);
try {

@@ -14,0 +17,0 @@ logger.debug("Process was running %s seconds before agent was loaded.",

3

lib/feature_flags.js

@@ -6,3 +6,4 @@ 'use strict';

proxy: true,
custom_instrumentation: false,
mysql_pool: false,
custom_instrumentation: true,
postgres: false

@@ -9,0 +10,0 @@ };

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

if (agent.config.feature_flag.custom_instrumentation) {
transaction.webSegment = segment;
}
// the error tracer needs a URL for tracing, even though naming overwrites

@@ -44,0 +48,0 @@ transaction.url = request.url;

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

function wrapQueriable(queriable, name) {
// may not always be a 'queriable' object, but anything with a .query
// you should pass the appropriate name in for shimmer
shimmer.wrapMethod(queriable, name, 'query', function cb_wrapMethod(query) {
return tracer.segmentProxy(function cb_segmentProxy(/* arguments */) {
// the code below implicitly relies on a transaction,
// so bail early if there is none
//
// we also avoid zero-argument calls
if (!tracer.getTransaction() || arguments.length < 1) {
logger.trace('not tracing because outside a transaction in %s', name);
return query.apply(this, arguments);
}
var sqlString = '';
var queryVals = [];
// these are used in the onEnd function
var userCallback
, segment
;
// passed to .query
// ends the segment, and then calls the user callback
function onEnd(err) {
logger.trace({error: err}, 'mysql query result in %s', name);
var ret;
if (userCallback) ret = userCallback.apply(null, arguments);
segment.end(); // !m wraithan
return ret;
}
function checkFunc(maybeFunc) {
var out;
if (typeof maybeFunc === 'function') {
out = tracer.callbackProxy(maybeFunc);
}
return out;
}
// This is just a massive argument hunt
// because you can call .query in many ways.
//
// You should populate `userCallback` after this block with a callback.
// Optionally you may populate `queryVals` and `sqlString`.
// The value in `sqlString` will show up in the UI
var vargs = [];
if (arguments.length === 1 && typeof arguments[0] === 'object') {
// .query(query)
// query query is a Query object and contains ._callback and .sql
userCallback = checkFunc(arguments[0]._callback);
arguments[0]._callback = onEnd;
vargs.push(arguments[0]);
} else if (arguments.length === 1) {
// either .query(callback) or .query(sql)
// in the latter case we append our own callback for instrumentation
if (!(userCallback = checkFunc(arguments[0]))) {
vargs.push(arguments[0]);
}
vargs.push(onEnd);
} else if (arguments.length === 2) {
// .query(sql, callback) or .query(sql, values)
// in the latter case we append our own callback for instrumentation
vargs.push(sqlString = arguments[0]);
if (!(userCallback = checkFunc(arguments[1]))) {
vargs.push(arguments[1]);
}
vargs.push(onEnd);
} else {
// .query(sql, values, callback) or unknown
// in the latter case, we just omit measuring
vargs.push(sqlString = arguments[0]);
vargs.push(queryVals = arguments[1]);
if (!(userCallback = checkFunc(arguments[2]))) {
vargs.push(arguments[2]);
} else {
vargs.push(onEnd);
}
}
logger.trace({query: sqlString}, 'wrapping query arguments in %s', name);
// name the metric
var ps = parseSql(MYSQL.PREFIX, sqlString);
var segmentName = MYSQL.STATEMENT + ps.model + '/' + ps.operation;
logger.trace({sql: sqlString, parsed: ps}, 'capturing sql in %s', name);
// we will end the segment in onEnd above
segment = tracer.addSegment(segmentName, ps.recordMetrics.bind(ps));
if (this.config && this.config.connectionConfig) {
segment.port = this.config.port || this.config.connectionConfig.port;
segment.host = this.config.host || this.config.connectionConfig.host;
}
return query.apply(queriable, vargs);
});
});
}
function getVargs(args) {
var callback;
var vargs = [];
if (args.length === 1) {
callback = args[0];
} else if (args.length === 2) {
vargs.push(args[0]);
callback = args[1];
} else {
vargs.push(args[0]);
vargs.push(args[1]);
callback = args[2];
}
logger.trace({args: args, vargs: vargs}, 'parsed getConnection arguments');
return {
vargs : vargs,
callback : callback,
};
}
function getConnectionHandler(dbObject, getConnectionMethod) {
return function wrap_getConnection() { // getConnection
var args = getVargs(arguments);
var getConnectionCallback;
// let's verify that we actually have a callback,
// otherwise we should just pass on wrapping it
//
// TODO: test case where no callback is supplied
var isCallback = args.callback && typeof args.callback === 'function';
// The mysql module has internal retry logic that will call
// getConnection again with our wrapped callback.
// We should avoid re-wrapping the callback when possible,
// although nothing bad happens when we fail this, it just
// makes stack traces a little better in errors.
if (!isCallback || !args.callback.__NR_original_callback) {
var proxiedCallback = tracer.callbackProxy(args.callback);
getConnectionCallback = function getConnectionCallback(err, connection) {
// we need to patch the connection objects .query method
wrapQueriable(connection, 'connection');
proxiedCallback(err, connection);
};
// tag so we can avoid re-wrapping
getConnectionCallback.__NR_original_callback = args.callback;
} else {
// the connection is already wrapped
logger.trace('getConnection callback already wrapped');
getConnectionCallback = args.callback;
}
args.vargs.push(getConnectionCallback);
return getConnectionMethod.apply(dbObject, args.vargs);
};
}
// FIXME: need a more general way of differentiating between driver versions
if (mysql && mysql.createConnection) {
// congratulations, you have node-mysql 2.0
shimmer.wrapMethod(mysql, 'mysql', 'createConnection', function cb_wrapMethod(createConnection) {
// FLAG: mysql_pool
if (agent.config &&
agent.config.feature_flag &&
agent.config.feature_flag.mysql_pool) {
shimmer.wrapMethod(mysql, 'mysql.prototype', 'createPoolCluster',
function cb_wrapMethod(createPoolCluster) {
// this is generally called outside of a transaction,
// so we don't need/care about preserving
// the continuation, but we do need to patch the returned object
return function not_in_transaction() {
var poolCluster = createPoolCluster.apply(mysql, arguments);
shimmer.wrapMethod(poolCluster, 'poolCluster', 'of',
function cb_wrapMethod(of) {
return function () {
var ofCluster = of.apply(poolCluster, arguments);
shimmer.wrapMethod(ofCluster, 'poolCluster', 'getConnection',
function cb_wrapMethod(getConnection) {
return getConnectionHandler(ofCluster, getConnection);
});
return ofCluster;
};
});
shimmer.wrapMethod(poolCluster, 'poolCluster', 'getConnection',
function cb_wrapMethod(getConnection) {
return getConnectionHandler(poolCluster, getConnection);
});
return poolCluster;
};
});
shimmer.wrapMethod(mysql, 'mysql', 'createPool',
function cb_wrapMethod(createPool) {
return function cb_segmentProxy() {
var pool = createPool.apply(mysql, arguments);
shimmer.wrapMethod(pool, 'pool', 'getConnection',
function cb_wrapMethod(getConnection) {
return getConnectionHandler(pool, getConnection);
});
// patch the pools .query method
wrapQueriable(pool, 'pool');
return pool;
};
});
} // FLAG: mysql_pool
shimmer.wrapMethod(mysql, 'mysql', 'createConnection',
function cb_wrapMethod(createConnection) {
return tracer.segmentProxy(function cb_segmentProxy() {
var connection = createConnection.apply(this, arguments);
shimmer.wrapMethod(connection, 'connection', 'query', function cb_wrapMethod(query) {
shimmer.wrapMethod(connection, 'connection', 'query',
function cb_wrapMethod(query) {
return tracer.segmentProxy(function cb_segmentProxy(sql, values, callback) {

@@ -23,0 +248,0 @@

@@ -76,2 +76,2 @@ 'use strict';

});
};
};

@@ -93,2 +93,3 @@ 'use strict';

WEB : 'WebTransaction',
BACKGROUND : 'OtherTransaction',
HTTP : 'HttpDispatcher',

@@ -95,0 +96,0 @@ CONTROLLER : 'Controller',

@@ -25,3 +25,2 @@ 'use strict';

'pg',
'pg.js',
'redis',

@@ -56,8 +55,14 @@ 'restify' ];

function _postLoad(agent, nodule, name) {
var instrumentation;
var base = path.basename(name);
// to allow for instrumenting both 'pg' and 'pg.js'.
if (name === 'pg.js') instrumentation = 'pg';
else instrumentation = base;
// necessary to prevent instrument() from causing an infinite loop
if (INSTRUMENTATION.indexOf(base) !== -1) {
if (INSTRUMENTATION.indexOf(instrumentation) !== -1) {
logger.trace('Instrumenting %s.', base);
var filename = path.join(__dirname, 'instrumentation', base + '.js');
var filename = path.join(__dirname, 'instrumentation', instrumentation + '.js');
instrument(agent, base, filename, nodule);

@@ -64,0 +69,0 @@ }

@@ -50,2 +50,3 @@ 'use strict';

this.webSegment = null;
this.bgSegment = null;
}

@@ -144,2 +145,13 @@

Transaction.prototype.setBackgroundName = function setBackgroundName(name, group) {
var fullName = NAMES.BACKGROUND + NAMES.ACTION_DELIMITER + group + NAMES.ACTION_DELIMITER + name;
var normalizer = this.agent.transactionNameNormalizer;
if (normalizer.isIgnored(fullName)) this.ignore = true;
this.name = normalizer.normalize(fullName);
if (this.forceIgnore === true || this.forceIgnore === false) {
this.ignore = this.forceIgnore;
}
};
/**

@@ -146,0 +158,0 @@ * Measure the duration of an operation named by a metric, optionally

@@ -172,3 +172,7 @@ 'use strict';

*/
Tracer.prototype.transactionNestProxy = function transactionNestProxy(handler) {
Tracer.prototype.transactionNestProxy = function transactionNestProxy(type, handler) {
if (handler === undefined && typeof type === 'function') {
handler = type;
type = undefined;
}
// if there's no handler, there's nothing to proxy.

@@ -185,9 +189,15 @@ if (!handler) return;

}
var transaction = self.getTransaction();
var transaction = self.getTransaction() || new Transaction(self.agent)
, proxied = this
, args = self.slice(arguments)
;
if (transaction) {
if ((type === 'web' && transaction.bgSegment) || (type === 'bg' && transaction.webSegment)) {
transaction = new Transaction(self.agent);
}
} else {
transaction = new Transaction(self.agent);
}
var proxied = this;
var args = self.slice(arguments);
var returned;
var returned;
namespace.bind(function cb_bind() {

@@ -210,2 +220,29 @@ self.setTransaction(transaction);

Tracer.prototype.transactionForceNewProxy = function transactionNestProxy(type, handler) {
// if there's no handler, there's nothing to proxy.
if (!handler) return;
var self = this;
var wrapped = function wrapTransactionInvocation() {
var transaction = new Transaction(self.agent)
, proxied = this
, args = self.slice(arguments)
;
var returned;
namespace.bind(function cb_bind() {
self.setTransaction(transaction);
self.setSegment(transaction.getTrace().root);
returned = namespace.bind(handler).apply(proxied, args);
}, Object.create(null))();
return returned;
};
wrapped[ORIGINAL] = handler;
return wrapped;
};
/**

@@ -212,0 +249,0 @@ * Use segmentProxy to wrap a closure that is a top-level handler that is

@@ -11,3 +11,3 @@ /**

*/
app_name : ['éxample'],
app_name : ['My Application'],
/**

@@ -14,0 +14,0 @@ * Your New Relic license key.

@@ -0,1 +1,11 @@

### v1.10.0 (2014-08-15):
* Custom instrumentation
The agent now supports the ability to annotate application code to provide
customized instrumentation. This includes the ability to time both web and
background transactions, and add tracers to measure activity within
transactions like querying a database. Documentation available at
https://docs.newrelic.com/docs/agents/nodejs-agent/supported-features/nodejs-custom-instrumentation
### v1.9.2 (2014-08-08):

@@ -2,0 +12,0 @@

{
"name": "newrelic",
"version": "1.9.2",
"version": "1.10.0",
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",

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

@@ -379,2 +379,61 @@ [![npm status badge](https://nodei.co/npm/newrelic.png?stars=true&downloads=true)](https://nodei.co/npm/newrelic/)

### Custom Instrumentation
Custom transaction should be used for instrumenting `socket.io` or other
varieties of socket servers, and background jobs. These are things that the
agent can't automatically instrument because without your knowledge of your
application, the agent can't tell when they should begin and end.
Read more at:
https://docs.newrelic.com/docs/agents/nodejs-agent/supported-features/nodejs-custom-instrumentation
#### newrelic.createWebTransaction(url, handle)
`url` is the name of the web transaction. It should be pretty static, not
including anything like user ids or any other data that is very specific to the
request. `handle` is the function you'd like to wrap in the web transaction.
Both custom and auto instrumentation will be captured as part of the
transaction.
If called within an active web transaction, it will act as a nested tracer. If
called within an active background transaction, it will create a new,
independent transaction and any calls within the `handle` will be bound to the
new web transaction.
Custom transactions **must** be ended manually by calling `endTransaction()`.
Timing for custom transaction starts from when the returned wrapped function is
called until `endTransaction()` is called.
#### newrelic.createBackgroundTransaction(name, [group], handle)
`name` is the name of the job. It should be pretty static, and not include job
ids or anything very specific to that run of the job. `group` is optional, and
allows you to group types of jobs together. This should follow similar rules as
the `name`. `handle` is a function that encompases your background job. Both
custom and auto instrumentation will be captured as part of the transaction.
If called within an active background transaction, it will act as a nested
tracer. If called within an active web transaction, it will create a new
transaction and any calls within the `handle` will be bound to the new,
independent background transaction.
Custom transactions **must** be ended manually by calling `endTransaction()`.
Timing for custom transaction starts from when the returned wrapped function is
called until `endTransaction()` is called.
#### newrelic.endTransaction()
This takes no arguments and must be called to end any custom transaction. It
will detect what kind of transaction was active and end it.
#### newrelic.createTracer(name, handle)
`name` is the name of the tracer. It will show up as a segment in your
transaction traces and create its own metric. `handle` is the function to be
bound to the tracer.
Timing is from when `createTracer` is called until the `handle` done executing.
This should be called inside of a transaction to get data. If it is called
outside of a transaction it will just pass through.
### The fine print

@@ -381,0 +440,0 @@

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

// Normally createTracer returns the a wrapped callback, instead we should just
// Normally the follow 3 calls return a wrapped callback, instead we should just
// return the callback in its unwrapped state.

@@ -44,3 +44,3 @@ Stub.prototype.createTracer = function(name, callback) {

Stub.prototype.createWebTransaction = function(name, callback) {
Stub.prototype.createWebTransaction = function(url, callback) {
logger.debug('Not calling createWebTransaction because New Relic is disabled.');

@@ -50,2 +50,7 @@ return callback;

Stub.prototype.createBackgroundTransaction = function(name, callback) {
logger.debug('Not calling createBackgroundTransaction because New Relic is disabled.');
return callback;
};
module.exports = Stub;

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

});
it('should record a metric for the custom segment', function (done) {
agent.on('transactionFinished', function (transaction) {
expect(transaction.metrics.unscoped).to.have.property('Custom/custom:segment');
done();
});
helper.runInTransaction(agent, function (transaction) {
var markedFunction = api.createTracer('custom:segment', function () {
transaction.end();
});
markedFunction();
});
});
});

@@ -135,3 +149,3 @@

});
expect(agent.tracer.getTransaction()).to.not.exist;
txHandler();

@@ -207,10 +221,216 @@ });

it('endTransaction should not throw an exception if there is no transaction active', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.not.exist;
expect(function () {
it('should create proper metrics', function (done) {
var txHandler = api.createWebTransaction('/custom/transaction', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.exist;
var expectedMetrics = [
{"name": "WebTransaction"},
{"name": "HttpDispatcher"},
{"name": "WebTransaction/Custom//custom/transaction"},
{"name": "Apdex/null"},
{"name": "Apdex"},
{"name": "WebTransaction/Custom//custom/transaction", "scope": "WebTransaction/Custom//custom/transaction"}
];
tx.end();
tx.metrics.toJSON().forEach(function (element, index) {
expect(element[0]).to.be.deep.equal(expectedMetrics[index]);
});
done();
});
expect(agent.tracer.getTransaction()).to.not.exist;
txHandler();
});
it('it should create a new transaction when nested within a background transaction', function (done) {
var bgHandler = api.createBackgroundTransaction('background:job', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.exist;
expect(tx.name).to.be.equal('OtherTransaction/Nodejs/background:job');
expect(tx.webSegment).to.not.exist;
expect(tx.bgSegment).to.exist;
var webHandler = api.createWebTransaction('/custom/transaction', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.exist;
expect(tx.url).to.be.equal('/custom/transaction');
expect(tx.webSegment).to.exist;
expect(tx.bgSegment).to.not.exist;
// clean up tx so it doesn't cause other problems
tx.end();
done();
});
webHandler();
// clean up tx so it doesn't cause other problems
tx.end();
});
expect(agent.tracer.getTransaction()).to.not.exist;
bgHandler();
});
});
describe('when creating an background transaction', function () {
it('should return a function', function () {
var txHandler = api.createBackgroundTransaction('background:job', function () {});
expect(txHandler).to.be.a('function');
});
it('should create a transaction', function (done) {
var txHandler = api.createBackgroundTransaction('background:job', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.exist;
expect(tx.name).to.be.equal('OtherTransaction/Nodejs/background:job');
// clean up tx so it doesn't cause other problems
tx.end();
done();
});
expect(agent.tracer.getTransaction()).to.not.exist;
txHandler();
});
it('should create an outermost segment', function (done) {
var txHandler = api.createBackgroundTransaction('background:job', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.exist;
var trace = tx.getTrace();
expect(trace.root.children).to.have.length(1);
// clean up tx so it doesn't cause other problems
tx.end();
done();
});
txHandler();
});
it('should respect the in play transaction and not create a new one', function (done) {
var txHandler = api.createBackgroundTransaction('background:job', function (outerTx) {
var tx = agent.tracer.getTransaction();
expect(tx).to.be.equal(outerTx);
var trace = tx.getTrace();
expect(trace.root.children).to.have.length(1);
done();
});
helper.runInTransaction(agent, function (transaction) {
txHandler(transaction);
transaction.end();
});
});
it('should nest its segment within an in play segment', function (done) {
var txHandler = api.createBackgroundTransaction('background:job', function (outerTx) {
var tx = agent.tracer.getTransaction();
expect(tx).to.be.equal(outerTx);
var trace = tx.getTrace();
expect(trace.root.children).to.have.length(1);
var child = trace.root.children[0];
expect(child.name).to.equal('outer');
expect(child.children).to.have.length(1);
done();
});
helper.runInTransaction(agent, function (transaction) {
agent.tracer.addSegment('outer');
txHandler(transaction);
transaction.end();
});
});
it('should be ended by calling endTransaction', function (done) {
var txHandler = api.createWebTransaction('background:job', function () {
var tx = agent.tracer.getTransaction();
expect(tx.isActive()).to.be.true;
api.endTransaction();
}).to.not.throw;
expect(tx.isActive()).to.be.false;
done();
});
txHandler();
});
it('should create proper metrics with default group name', function (done) {
var txHandler = api.createBackgroundTransaction('background:job', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.exist;
var expectedMetrics = [
{"name": "OtherTransaction/Nodejs/background:job"},
{"name": "OtherTransaction/all"},
{"name": "OtherTransaction/Nodejs/all"},
{"name": "OtherTransaction/Nodejs/background:job", "scope": "OtherTransaction/Nodejs/background:job"}
];
tx.end();
tx.metrics.toJSON().forEach(function (element, index) {
expect(element[0]).to.be.deep.equal(expectedMetrics[index]);
});
done();
});
expect(agent.tracer.getTransaction()).to.not.exist;
txHandler();
});
it('should create proper metrics with group name', function (done) {
var txHandler = api.createBackgroundTransaction('background:job', 'thinger', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.exist;
var expectedMetrics = [
{"name": "OtherTransaction/thinger/background:job"},
{"name": "OtherTransaction/all"},
{"name": "OtherTransaction/thinger/all"},
{"name": "OtherTransaction/thinger/background:job", "scope": "OtherTransaction/thinger/background:job"}
];
tx.end();
tx.metrics.toJSON().forEach(function (element, index) {
expect(element[0]).to.be.deep.equal(expectedMetrics[index]);
});
done();
});
expect(agent.tracer.getTransaction()).to.not.exist;
txHandler();
});
it('it should create a new transaction when nested within a background transaction', function (done) {
var webHandler = api.createWebTransaction('/custom/transaction', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.exist;
expect(tx.url).to.be.equal('/custom/transaction');
expect(tx.webSegment).to.exist;
expect(tx.bgSegment).to.not.exist;
var bgHandler = api.createBackgroundTransaction('background:job', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.exist;
expect(tx.name).to.be.equal('OtherTransaction/Nodejs/background:job');
expect(tx.webSegment).to.not.exist;
expect(tx.bgSegment).to.exist;
// clean up tx so it doesn't cause other problems
tx.end();
done();
});
bgHandler();
// clean up tx so it doesn't cause other problems
tx.end();
});
expect(agent.tracer.getTransaction()).to.not.exist;
webHandler();
});
});
it('endTransaction should not throw an exception if there is no transaction active', function () {
var tx = agent.tracer.getTransaction();
expect(tx).to.not.exist;
expect(function () {
api.endTransaction();
}).to.not.throw;
});
});

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

it("should export 11 API calls", function () {
expect(Object.keys(api.constructor.prototype).length).equal(11);
expect(Object.keys(api.constructor.prototype).length).equal(12);
});

@@ -113,2 +113,14 @@

it("shouldn't throw when a custom background transaction is added", function () {
expect(function () {
api.createBackgroundTransaction('name', function nop(){});
}).not.throws();
});
it("should return a function when calling createBackgroundTransaction", function () {
function myNop () {}
var retVal = api.createBackgroundTransaction('name', myNop);
expect(retVal).to.be.equal(myNop);
});
it("shouldn't throw when a transaction is ended", function () {

@@ -115,0 +127,0 @@ expect(function () {

@@ -16,2 +16,3 @@ var flags = require('../lib/feature_flags.js');

'custom_instrumentation',
'mysql_pool',
'postgres'

@@ -18,0 +19,0 @@ ];

@@ -115,3 +115,7 @@ 'use strict';

*/
runInTransaction : function runInTransaction(agent, callback) {
runInTransaction : function runInTransaction(agent, type, callback) {
if (callback === undefined && typeof type === 'function') {
callback = type;
type = undefined;
}
if (!(agent && callback)) {

@@ -118,0 +122,0 @@ throw new TypeError("Must include both agent and function!");

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