newrelic 3.1.0 → 4.0.0

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/.travis.yml CHANGED
@@ -1,7 +1,5 @@
1
1
  language: node_js
2
2
  node_js:
3
- - "0.10"
4
- - "0.12"
5
3
  - "4"
6
4
  - "5"
7
5
  - "6"
@@ -18,14 +16,6 @@ env:
18
16
  - SUITE=versioned
19
17
  matrix:
20
18
  exclude:
21
- - node_js: "0.10"
22
- env: SUITE=security
23
- - node_js: "0.10"
24
- env: SUITE=lint
25
- - node_js: "0.12"
26
- env: SUITE=security
27
- - node_js: "0.12"
28
- env: SUITE=lint
29
19
  - node_js: "4"
30
20
  env: SUITE=security
31
21
  - node_js: "4"
@@ -3,6 +3,18 @@
3
3
  This guide is intended to help with upgrading major versions of the Node Agent.
4
4
  This information can also be found on [our documentation website][upgrade-doc].
5
5
 
6
+ ## Upgrading to Agent v4
7
+
8
+ ### Breaking Changes
9
+
10
+ **Upgraded https-proxy-agent from v0 to v2**: This dependency has been updated
11
+ due to a security issue in the version of `https-proxy-agent` the New Relic Node.js
12
+ agent used. `https-proxy` v2 is incompatible with node v0.10 and v0.12,
13
+ requiring deprecation of those versions for the agent. There is no required
14
+ action to migrate from v3 to v4 of New Relic's Node.js agent.
15
+
16
+ --------------------------------------------------------------------------------
17
+
6
18
  ## Upgrading to Agent v3
7
19
 
8
20
  ### Breaking Changes
package/NEWS.md CHANGED
@@ -1,3 +1,68 @@
1
+ ### 4.0.0 (2018-04-12):
2
+
3
+ * BREAKING: Updated the version of `https-proxy-agent` to v2.x - Dropped support for v0.10 and v0.12 of node.
4
+
5
+ The version of `https-proxy-agent` used in the agent has a known security
6
+ issue you can read about here: https://snyk.io/vuln/npm:https-proxy-agent:20180402
7
+ In order to resolve this issue, the dependency had to be updated to at least
8
+ v2.2.0, which only supported node versions >=4. The update to this dependency
9
+ forces the incompatibility of the agent with versions 0.10 and 0.12 of node.
10
+
11
+ In order to use use the Node.js agent, please upgrade node to version >=4, or you can
12
+ continue to use the agent on node versions 0.10 and 0.12 by pinning the agent
13
+ to v3.
14
+
15
+ You can read more about the issue here: https://docs.newrelic.com/docs/using-new-relic/new-relic-security/security-bulletins/security-bulletin-nr18-08
16
+
17
+ ### 3.3.1 (2018-04-10):
18
+
19
+ * Added a type check to attribute validation, restricting values to primitive types
20
+ (but not `undefined`).
21
+
22
+ Previously the agent was only enforcing byte limits on string values, resulting
23
+ in overly large arrays being collected. This brings the agent in line with other
24
+ language agents.
25
+
26
+ * The `DatastoreShim` will now respect specified `after` handlers.
27
+
28
+ Previously on methods like `DatastoreShim#recordQuery` the `after` handler would
29
+ be dropped. The property is now correctly propagated to the underlying
30
+ `Shim#record` call.
31
+
32
+ * The agent will now check that a specified parent segment is part of an active
33
+ segment before running a method under instrumentation.
34
+
35
+ Previously the agent would unconditionally run a method under a specified
36
+ parent. The shim expects the parent to exist and be active, and will throw
37
+ errors in the case where the parent belongs to an inactive transaction.
38
+
39
+ ### 3.3.0 (2018-03-27):
40
+
41
+ * Added `newrelic.startSegment()` which replaces `newrelic.createTracer()`.
42
+
43
+ This new API method allows you to create custom segments using either callbacks
44
+ or promises.
45
+
46
+ * Fixed bug in `pre` route config option in Hapi instrumentation.
47
+
48
+ Only applies to Hapi v16 and below. The `pre` handler wrapping was not properly
49
+ returning in cases when the element was a string referring to a registered server
50
+ method, and as a result these elements would be replaced with `undefined`.
51
+
52
+ ### 3.2.0 (2018-03-14):
53
+
54
+ * Added [`@newrelic/koa`](https://github.com/newrelic/node-newrelic-koa) as a
55
+ dependency.
56
+
57
+ This introduces instrumentation for **Koa v2.0.0** or higher. It will be treated
58
+ as first-party instrumentation within the agent, but publishing it as a
59
+ separate module allows it to be installed independently according to users' needs.
60
+
61
+ * Refactored instrumentation hooks to work with modules.
62
+
63
+ With this change it is now possible to link against external instrumentation
64
+ modules.
65
+
1
66
  ### 3.1.0 (2018-03-13):
2
67
 
3
68
  * Promise based web framework middleware instrumentation now supports callback
package/README.md CHANGED
@@ -708,15 +708,17 @@ returned transaction is a custom one, started with either `startWebTransaction`
708
708
  or `startBackgroundTransaction`, then `transaction.end()` must be called to
709
709
  end the transaction.
710
710
 
711
- #### newrelic.createTracer(name, handle)
711
+ #### newrelic.startSegment(name, record, handler, callback)
712
712
 
713
- `name` is the name of the tracer. It will show up as a segment in your
714
- transaction traces and create its own metric. `handle` is the function to be
715
- bound to the tracer.
713
+ `name` is the name of the segment. `record` is a boolean value signalling
714
+ whether or not to record the segment as a metric. `handler` is the function
715
+ being recorded. `callback` is an optional function that is passed to the
716
+ handler and fired after all other work is complete.
716
717
 
717
- Timing is from when `createTracer` is called until the `handle` done executing.
718
- This should be called inside of a transaction to get data. If it is called
719
- outside of a transaction it will just pass through.
718
+ Timing is from when `startSegment` is called until the `handler` is done
719
+ executing, or when the `callback` is fired, if it's supplied. This method
720
+ should be called inside of a transaction to get data. If it is called outside
721
+ of a transaction it will just pass through.
720
722
 
721
723
  #### newrelic.recordMetric(name, value)
722
724
 
package/api.js CHANGED
@@ -629,13 +629,23 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader() {
629
629
  return out
630
630
  }
631
631
 
632
+ API.prototype.createTracer = util.deprecate(
633
+ createTracer, [
634
+ 'API#createTracer is being deprecated!',
635
+ 'Please use API#startSegment for segment creation.'
636
+ ].join(' ')
637
+ )
638
+
632
639
  /**
633
640
  * This creates a new tracer with the passed in name. It then wraps the
634
641
  * callback and binds it to the current transaction and segment so any further
635
642
  * custom instrumentation as well as auto instrumentation will also be able to
636
643
  * find the current transaction and segment.
644
+ *
645
+ * @memberof API#
646
+ * @deprecated use {@link API#startSegment} instead
637
647
  */
638
- API.prototype.createTracer = function createTracer(name, callback) {
648
+ function createTracer(name, callback) {
639
649
  var metric = this.agent.metrics.getOrCreateMetric(
640
650
  NAMES.SUPPORTABILITY.API + '/createTracer'
641
651
  )
@@ -687,6 +697,70 @@ API.prototype.createTracer = function createTracer(name, callback) {
687
697
  return arity.fixArity(callback, tracer.bindFunction(callback, segment, true))
688
698
  }
689
699
 
700
+ /**
701
+ * Wraps the given handler in a segment which may optionally be turned into a
702
+ * metric.
703
+ *
704
+ * @example
705
+ * newrelic.startSegment('mySegment', false, function handler() {
706
+ * // The returned promise here will signify the end of the segment.
707
+ * return myAsyncTask().then(myNextTask)
708
+ * })
709
+ *
710
+ * @param {string} name
711
+ * The name to give the new segment. This will also be the name of the metric.
712
+ *
713
+ * @param {bool} record
714
+ * Indicates if the segment should be recorded as a metric. Metrics will show
715
+ * up on the transaction breakdown table and server breakdown graph. Segments
716
+ * just show up in transaction traces.
717
+ *
718
+ * @param {function(cb) -> ?Promise} handler
719
+ * The function to track as a segment.
720
+ *
721
+ * @param {function} [callback]
722
+ * An optional callback for the handler. This will indicate the end of the
723
+ * timing if provided.
724
+ *
725
+ * @return {*} Returns the result of calling `handler`.
726
+ */
727
+ API.prototype.startSegment = function startSegment(name, record, handler, callback) {
728
+ this.agent.metrics.getOrCreateMetric(
729
+ NAMES.SUPPORTABILITY.API + '/startSegment'
730
+ ).incrementCallCount()
731
+
732
+ // Check that we have usable arguments.
733
+ if (!name || typeof handler !== 'function') {
734
+ logger.warn('Name and handler function are both required for startSegment')
735
+ if (typeof handler === 'function') {
736
+ return handler(callback)
737
+ }
738
+ return
739
+ }
740
+ if (callback && typeof callback !== 'function') {
741
+ logger.warn('If using callback, it must be a function')
742
+ return handler(callback)
743
+ }
744
+
745
+ // Are we inside a transaction?
746
+ if (!this.shim.getActiveSegment()) {
747
+ logger.debug('startSegment(%j) called outside of a transaction, not recording.', name)
748
+ return handler(callback)
749
+ }
750
+
751
+ // Create the segment and call the handler.
752
+ var wrappedHandler = this.shim.record(handler, function handlerNamer(shim) {
753
+ return {
754
+ name: name,
755
+ recorder: record ? customRecorder : null,
756
+ callback: callback ? shim.FIRST : null,
757
+ promise: !callback
758
+ }
759
+ })
760
+
761
+ return wrappedHandler(callback)
762
+ }
763
+
690
764
  API.prototype.createWebTransaction = util.deprecate(
691
765
  createWebTransaction, [
692
766
  'API#createWebTransaction is being deprecated!',
@@ -713,7 +787,7 @@ API.prototype.createWebTransaction = util.deprecate(
713
787
  name and not iclude any variable parameters.
714
788
  * @param {Function} handle Function that represents the transaction work.
715
789
  *
716
- * @memberOf API#
790
+ * @memberof API#
717
791
  *
718
792
  * @deprecated since version 2.0
719
793
  */
@@ -9,10 +9,13 @@ fi
9
9
  # fi
10
10
 
11
11
  set -f
12
- DIRECTORY="test/versioned/**/*.tap.js"
12
+ directories=()
13
13
  if [[ "$1" != '' ]]; then
14
- DIRECTORY="test/versioned/${1}/*.tap.js"
14
+ directories=(
15
+ "test/versioned/${1}"
16
+ "node_modules/@newrelic/${1}/tests/versioned"
17
+ )
15
18
  fi
16
19
 
17
- export NEW_RELIC_HOME=`pwd`/test/versioned
18
- time ./node_modules/.bin/versioned-tests $VERSIONED_MODE -i 2 $DIRECTORY
20
+ export AGENT_PATH=`pwd`
21
+ time ./node_modules/.bin/versioned-tests $VERSIONED_MODE -i 2 ${directories[@]}
package/index.js CHANGED
@@ -42,10 +42,10 @@ function initialize() {
42
42
  preAgentTime
43
43
  )
44
44
 
45
- // TODO: Update this check when Node v0.10 is deprecated.
46
- if (psemver.satisfies('<0.10.0')) {
45
+ // TODO: Update this check when Node v4 is deprecated.
46
+ if (psemver.satisfies('<4.0.0')) {
47
47
  message = "New Relic for Node.js requires a version of Node equal to or\n" +
48
- "greater than 0.10.0. Not starting!"
48
+ "greater than 4.0.0. Not starting!"
49
49
 
50
50
  logger.error(message)
51
51
  throw new Error(message)
@@ -633,7 +633,12 @@ module.exports = function initialize(agent, http, moduleName) {
633
633
  wrapRequest.bind(null, agent)
634
634
  )
635
635
 
636
- if (psemver.satisfies('>=8')) {
636
+ // Upon updating to https-proxy-agent v2, we are now using
637
+ // agent-base v4, which patches https.get to use https.request.
638
+ // https://github.com/TooTallNate/node-agent-base/commit/7de92df780e147d46185281d26a1b534b3aaa97e
639
+ // This means we need to skip instrumenting to avoid double
640
+ // instrumenting external requests.
641
+ if (moduleName !== 'https' && psemver.satisfies('>=8')) {
637
642
  shimmer.wrapMethod(
638
643
  http,
639
644
  'http',
@@ -146,6 +146,10 @@ function wrapPreHandlers(shim, container, path) {
146
146
  return _wrapPreHandler(handler)
147
147
  })
148
148
  }
149
+ // The 'pre' option also allows strings pointing to methods registered via
150
+ // server.method() (ie: 'methodName(args)'). For the most part, these should
151
+ // be simple utility functions, but may be something we want to wrap in the future.
152
+ return container
149
153
 
150
154
  function _wrapPreHandler(handler) {
151
155
  return shim.recordMiddleware(
@@ -1,26 +1,30 @@
1
1
  'use strict'
2
2
 
3
+ var MODULE_TYPE = require('./shim/constants').MODULE_TYPE
4
+
3
5
  // Return a new copy of this array every time we're called
4
6
  module.exports = function instrumentations() {
5
- return [
6
- 'connect',
7
- 'bluebird',
8
- 'director',
9
- 'express',
10
- 'generic-pool',
11
- 'hapi',
12
- 'ioredis',
13
- 'memcached',
14
- 'mongodb',
15
- 'mysql',
16
- 'node-cassandra-cql',
17
- 'cassandra-driver',
18
- 'pg',
19
- 'q',
20
- 'redis',
21
- 'restify',
22
- 'oracle',
23
- 'vision',
24
- 'when'
25
- ]
7
+ return {
8
+ 'amqplib': {type: MODULE_TYPE.MESSAGE},
9
+ 'connect': {type: MODULE_TYPE.WEB_FRAMEWORK},
10
+ 'bluebird': {type: null},
11
+ 'director': {type: MODULE_TYPE.WEB_FRAMEWORK},
12
+ 'express': {type: MODULE_TYPE.WEB_FRAMEWORK},
13
+ 'generic-pool': {type: MODULE_TYPE.GENERIC},
14
+ 'hapi': {type: MODULE_TYPE.WEB_FRAMEWORK},
15
+ 'ioredis': {type: MODULE_TYPE.DATASTORE},
16
+ 'koa': {module: '@newrelic/koa'},
17
+ 'memcached': {type: MODULE_TYPE.DATASTORE},
18
+ 'mongodb': {type: MODULE_TYPE.DATASTORE},
19
+ 'mysql': {type: MODULE_TYPE.DATASTORE},
20
+ 'node-cassandra-cql': {type: MODULE_TYPE.DATASTORE},
21
+ 'cassandra-driver': {type: MODULE_TYPE.DATASTORE},
22
+ 'pg': {type: MODULE_TYPE.DATASTORE},
23
+ 'q': {type: null},
24
+ 'redis': {type: MODULE_TYPE.DATASTORE},
25
+ 'restify': {type: MODULE_TYPE.WEB_FRAMEWORK},
26
+ 'oracle': {type: null},
27
+ 'vision': {type: MODULE_TYPE.WEB_FRAMEWORK},
28
+ 'when': {type: null}
29
+ }
26
30
  }
@@ -408,6 +408,7 @@ function recordOperation(nodule, properties, opSpec) {
408
408
  name: opSpec.name || fnName || 'other',
409
409
  parameters: opSpec.parameters,
410
410
  callback: opSpec.callback,
411
+ after: 'after' in opSpec ? opSpec.after : null,
411
412
  promise: 'promise' in opSpec ? opSpec.promise : null,
412
413
  record: opSpec.record
413
414
  }
@@ -716,6 +717,7 @@ function _recordQuery(suffix, nodule, properties, querySpec) {
716
717
  callback: 'callback' in queryDesc ? queryDesc.callback : null,
717
718
  rowCallback: 'rowCallback' in queryDesc ? queryDesc.rowCallback : null,
718
719
  stream: 'stream' in queryDesc ? queryDesc.stream : null,
720
+ after: 'after' in queryDesc ? queryDesc.after : null,
719
721
  promise: 'promise' in queryDesc ? queryDesc.promise : null,
720
722
  internal: 'internal' in queryDesc ? queryDesc.internal : false,
721
723
  opaque: 'opaque' in queryDesc ? queryDesc.opaque : false
@@ -742,6 +744,7 @@ function _recordQuery(suffix, nodule, properties, querySpec) {
742
744
  callback: 'callback' in queryDesc ? queryDesc.callback : null,
743
745
  rowCallback: 'rowCallback' in queryDesc ? queryDesc.rowCallback : null,
744
746
  stream: 'stream' in queryDesc ? queryDesc.stream : null,
747
+ after: 'after' in queryDesc ? queryDesc.after : null,
745
748
  promise: 'promise' in queryDesc ? queryDesc.promise : null,
746
749
  internal: 'internal' in queryDesc ? queryDesc.internal : true,
747
750
  opaque: 'opaque' in queryDesc ? queryDesc.opaque : false,
package/lib/shim/shim.js CHANGED
@@ -887,7 +887,15 @@ function record(nodule, properties, recordNamer) {
887
887
  segDesc = new specs.RecorderSpec(segDesc)
888
888
 
889
889
  // See if we're in an active transaction.
890
- var parent = segDesc.parent || shim.getActiveSegment()
890
+ var parent
891
+ if (segDesc.parent) {
892
+ // We only want to continue recording in a transaction if the
893
+ // transaction is active.
894
+ parent = segDesc.parent.transaction.isActive() ? segDesc.parent : null
895
+ } else {
896
+ parent = shim.getActiveSegment()
897
+ }
898
+
891
899
  if (!parent) {
892
900
  shim.logger.debug('Not recording function %s, not in a transaction.', name)
893
901
  return fn.apply(this, arguments)
package/lib/shimmer.js CHANGED
@@ -3,7 +3,7 @@
3
3
  var path = require('path')
4
4
  var fs = require('./util/unwrapped-core').fs
5
5
  var logger = require('./logger').child({component: 'shimmer'})
6
- var INSTRUMENTATION = require('./instrumentations')()
6
+ var INSTRUMENTATIONS = require('./instrumentations')()
7
7
  var properties = require('./util/properties')
8
8
  var shims = require('./shim')
9
9
 
@@ -32,26 +32,6 @@ var MODULE_TYPE = shims.constants.MODULE_TYPE
32
32
 
33
33
  var registeredInstrumentations = Object.create(null)
34
34
 
35
- // TODO: is there a better way to do this?
36
- var instrumentationTypes = {
37
- 'amqplib': MODULE_TYPE.MESSAGE,
38
- 'generic-pool': MODULE_TYPE.GENERIC,
39
- 'ioredis': MODULE_TYPE.DATASTORE,
40
- 'mongodb': MODULE_TYPE.DATASTORE,
41
- 'mysql': MODULE_TYPE.DATASTORE,
42
- 'redis': MODULE_TYPE.DATASTORE,
43
- 'memcached': MODULE_TYPE.DATASTORE,
44
- 'pg': MODULE_TYPE.DATASTORE,
45
- 'cassandra-driver': MODULE_TYPE.DATASTORE,
46
- 'node-cassandra-cql': MODULE_TYPE.DATASTORE,
47
- 'connect': MODULE_TYPE.WEB_FRAMEWORK,
48
- 'express': MODULE_TYPE.WEB_FRAMEWORK,
49
- 'restify': MODULE_TYPE.WEB_FRAMEWORK,
50
- 'director': MODULE_TYPE.WEB_FRAMEWORK,
51
- 'hapi': MODULE_TYPE.WEB_FRAMEWORK,
52
- 'vision': MODULE_TYPE.WEB_FRAMEWORK
53
- }
54
-
55
35
  var SHIM_TYPE_MAP = Object.create(null)
56
36
  SHIM_TYPE_MAP[MODULE_TYPE.GENERIC] = shims.Shim
57
37
  SHIM_TYPE_MAP[MODULE_TYPE.DATASTORE] = shims.DatastoreShim
@@ -380,18 +360,24 @@ var shimmer = module.exports = {
380
360
  })
381
361
 
382
362
  // Register all the first-party instrumentations.
383
- INSTRUMENTATION.forEach(function forEachInstrumentation(moduleName) {
384
- var fileName = path.join(__dirname, 'instrumentation', moduleName + '.js')
385
- shimmer.registerInstrumentation({
386
- moduleName: moduleName,
387
- type: instrumentationTypes[moduleName],
388
- onRequire: _firstPartyInstrumentation.bind(null, agent, fileName)
389
- })
363
+ Object.keys(INSTRUMENTATIONS).forEach(function forEachInstrumentation(moduleName) {
364
+ var instrInfo = INSTRUMENTATIONS[moduleName]
365
+ if (instrInfo.module) {
366
+ var hooks = require(instrInfo.module + '/nr-hooks')
367
+ hooks.forEach(shimmer.registerInstrumentation)
368
+ } else if (moduleName === 'amqplib') {
369
+ // TODO: Remove this code when amqplib instrumentation is made external.
370
+ require('./instrumentation/amqplib').selfRegister(shimmer)
371
+ } else {
372
+ var fileName = path.join(__dirname, 'instrumentation', moduleName + '.js')
373
+ shimmer.registerInstrumentation({
374
+ moduleName: moduleName,
375
+ type: instrInfo.type,
376
+ onRequire: _firstPartyInstrumentation.bind(null, agent, fileName)
377
+ })
378
+ }
390
379
  })
391
380
 
392
- // TODO: Remove this code when amqplib instrumentation is made external.
393
- require('./instrumentation/amqplib').selfRegister(shimmer)
394
-
395
381
  // Even though domain is a core module we add it as a registered
396
382
  // instrumentation to be lazy-loaded because we do not want to cause domain
397
383
  // usage.
@@ -51,7 +51,7 @@ TraceAttributes.prototype.get = function get(dest) {
51
51
  var attrCount = 0
52
52
  for (var key in this.attributes) { // eslint-disable-line guard-for-in
53
53
  var attr = this.attributes[key]
54
- if (!(attr.destinations & dest)) {
54
+ if (!(attr.destinations & dest) || !isValidType(attr.value)) {
55
55
  continue
56
56
  }
57
57
 
@@ -98,3 +98,15 @@ function truncate(val) {
98
98
  }
99
99
  return val
100
100
  }
101
+
102
+ /**
103
+ * Checks incoming attribute value against valid types:
104
+ * string, number, boolean, & null.
105
+ *
106
+ * @param {*} val
107
+ *
108
+ * @return {boolean}
109
+ */
110
+ function isValidType(val) {
111
+ return val === null || typeof val !== 'object' && val !== undefined
112
+ }
@@ -3,10 +3,16 @@
3
3
  var path = require('path')
4
4
  var logger = require('./logger')
5
5
  var NAMES = require('./metrics/names')
6
- var INSTRUMENTATIONS = require('./instrumentations')()
6
+ var INSTRUMENTATIONS = Object.keys(require('./instrumentations')())
7
7
  var properties = require('./util/properties')
8
8
 
9
9
 
10
+ // TODO: This should iterate over the registered instrumentations in the shimmer.
11
+ // As long as this file is executed after `bootstrapInstrumentation` is called
12
+ // the shimmer should have a complete list of all instrumentation names we
13
+ // hook into.
14
+
15
+
10
16
  module.exports = {
11
17
  check: check,
12
18
  createMetrics: createMetrics
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "3.1.0",
3
+ "version": "4.0.0",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "licenses": [
6
6
  {
@@ -96,7 +96,7 @@
96
96
  ],
97
97
  "homepage": "http://github.com/newrelic/node-newrelic",
98
98
  "engines": {
99
- "node": ">=0.10.0",
99
+ "node": ">=4.0.0",
100
100
  "npm": ">=2.0.0"
101
101
  },
102
102
  "directories": {
@@ -111,9 +111,10 @@
111
111
  "newrelic-naming-rules": "./bin/test-naming-rules.js"
112
112
  },
113
113
  "dependencies": {
114
+ "@newrelic/koa": "^1.0.0",
114
115
  "async": "^2.1.4",
115
116
  "concat-stream": "^1.5.0",
116
- "https-proxy-agent": "^0.3.6",
117
+ "https-proxy-agent": "^2.2.1",
117
118
  "json-stringify-safe": "^5.0.0",
118
119
  "readable-stream": "^2.1.4",
119
120
  "semver": "^5.3.0"
@@ -122,7 +123,7 @@
122
123
  "@newrelic/native-metrics": "^2.1.0"
123
124
  },
124
125
  "devDependencies": {
125
- "@newrelic/test-utilities": "git+https://github.com/newrelic/node-test-utilities.git",
126
+ "@newrelic/test-utilities": "^1.2.0",
126
127
  "JSV": "~4.0.2",
127
128
  "architect": "*",
128
129
  "benchmark": "^2.1.4",
@@ -140,6 +141,7 @@
140
141
  "jsdoc": "^3.4.0",
141
142
  "lodash": "^4.17.5",
142
143
  "memcached": ">=0.2.8",
144
+ "methods": "^1.1.2",
143
145
  "minami": "^1.1.1",
144
146
  "mkdirp": "*",
145
147
  "mocha": "^3.5.3",
package/stub_api.js CHANGED
@@ -30,7 +30,12 @@ for (var i = 0; i < length; i++) {
30
30
  Stub.prototype[functionName] = stubFunction(functionName)
31
31
  }
32
32
 
33
- Stub.prototype.createTracer = createTracer
33
+ Stub.prototype.createTracer = util.deprecate(
34
+ createTracer, [
35
+ 'API#createTracer is being deprecated!',
36
+ 'Please use API#startSegment for segment creation.'
37
+ ].join(' ')
38
+ )
34
39
  Stub.prototype.createWebTransaction = util.deprecate(
35
40
  createWebTransaction, [
36
41
  'API#createWebTransaction is being deprecated!',
@@ -47,6 +52,7 @@ Stub.prototype.createBackgroundTransaction = util.deprecate(
47
52
  'ending transactions.'
48
53
  ].join(' ')
49
54
  )
55
+ Stub.prototype.startSegment = startSegment
50
56
  Stub.prototype.startWebTransaction = startWebTransaction
51
57
  Stub.prototype.startBackgroundTransaction = startBackgroundTransaction
52
58
  Stub.prototype.getTransaction = getTransaction
@@ -81,6 +87,14 @@ function createBackgroundTransaction(name, group, callback) {
81
87
  return (callback === undefined) ? group : callback
82
88
  }
83
89
 
90
+ function startSegment(name, record, handler, callback) {
91
+ logger.debug('Not calling `startSegment` becuase New Relic is disabled.')
92
+ if (typeof handler === 'function') {
93
+ return handler(callback)
94
+ }
95
+ return null
96
+ }
97
+
84
98
  function startWebTransaction(url, callback) {
85
99
  logger.debug('Not calling startWebTransaction because New Relic is disabled.')
86
100
  if (typeof callback === 'function') {