newrelic 4.10.0 → 4.13.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.
Files changed (55) hide show
  1. package/.eslintrc +2 -0
  2. package/.npmignore +4 -0
  3. package/NEWS.md +89 -0
  4. package/api.js +88 -47
  5. package/bin/travis-setup.sh +14 -6
  6. package/index.js +12 -10
  7. package/lib/adaptive-sampler.js +28 -5
  8. package/lib/agent.js +199 -77
  9. package/lib/collector/api.js +228 -178
  10. package/lib/collector/facts.js +29 -9
  11. package/lib/collector/parse-response.js +24 -76
  12. package/lib/collector/remote-method.js +102 -72
  13. package/lib/collector/response.js +61 -0
  14. package/lib/collector/serverless.js +205 -0
  15. package/lib/config/attribute-filter.js +3 -1
  16. package/lib/config/default.js +14 -3
  17. package/lib/config/env.js +11 -3
  18. package/lib/config/index.js +103 -56
  19. package/lib/db/tracer.js +7 -0
  20. package/lib/errors/aggregator.js +9 -2
  21. package/lib/errors/index.js +6 -6
  22. package/lib/feature_flags.js +2 -0
  23. package/lib/harvest.js +526 -444
  24. package/lib/header-attributes.js +152 -0
  25. package/lib/instrumentation/amqplib.js +4 -3
  26. package/lib/instrumentation/aws-sdk.js +25 -0
  27. package/lib/instrumentation/core/http-outbound.js +12 -4
  28. package/lib/instrumentation/core/http.js +20 -126
  29. package/lib/instrumentation/restify.js +23 -4
  30. package/lib/instrumentations.js +1 -0
  31. package/lib/metrics/names.js +7 -6
  32. package/lib/metrics/normalizer.js +1 -2
  33. package/lib/metrics/recorders/http.js +4 -4
  34. package/lib/serverless/api-gateway.js +62 -0
  35. package/lib/serverless/aws-lambda.js +273 -0
  36. package/lib/serverless/config.js +0 -0
  37. package/lib/shim/constants.js +13 -1
  38. package/lib/shim/shim.js +16 -10
  39. package/lib/shim/specs/index.js +2 -2
  40. package/lib/shim/webframework-shim.js +7 -3
  41. package/lib/shimmer.js +15 -8
  42. package/lib/spans/aggregator.js +2 -2
  43. package/lib/system-info.js +15 -14
  44. package/lib/timer.js +7 -3
  45. package/lib/transaction/index.js +27 -5
  46. package/lib/transaction/trace/attributes.js +1 -4
  47. package/lib/util/label-parser.js +1 -1
  48. package/package-lock.json +6572 -0
  49. package/package.json +6 -13
  50. package/stub_api.js +6 -0
  51. package/lib/collector/constants.js +0 -10
  52. package/lib/metrics/recorders/cassandra.js +0 -40
  53. package/lib/metrics/recorders/express.js +0 -15
  54. package/lib/metrics/recorders/memcached.js +0 -48
  55. package/lib/metrics/recorders/redis.js +0 -48
package/.eslintrc CHANGED
@@ -8,6 +8,7 @@
8
8
  "ecmaVersion": 6
9
9
  },
10
10
  "rules": {
11
+ "indent": ["warn", 2, {"SwitchCase": 1}],
11
12
  "brace-style": "error",
12
13
  "comma-dangle": "off",
13
14
  "comma-style": ["error", "last"],
@@ -25,6 +26,7 @@
25
26
  "max-params": ["error", 5],
26
27
  "new-cap": "error",
27
28
  "no-console": "warn",
29
+ "no-debugger": "error",
28
30
  "no-else-return": "error",
29
31
  "no-floating-decimal": "error",
30
32
  "no-lonely-if": "error",
package/.npmignore ADDED
@@ -0,0 +1,4 @@
1
+ test
2
+ examples
3
+ out
4
+ Makefile
package/NEWS.md CHANGED
@@ -1,3 +1,92 @@
1
+ ### 4.13.1 (2019-04-23):
2
+
3
+ * Fixed bug where agent would stop sending data to New Relic servers when a connectivity
4
+ issue was encountered.
5
+
6
+ * The agent will no longer crash the process in the event of unexpected calls to the
7
+ harvest callback.
8
+
9
+ ### 4.13.0 (2018-12-20):
10
+
11
+ * Fixed clearing of active harvest via _stopHarvester()
12
+
13
+ * Fixed handling of harvest endpoints when not all fail.
14
+
15
+ * Added agent state "connecting" to indicate when handshake with New Relic servers
16
+ is starting. This can be triggered on startup and restarts.
17
+
18
+ * Added `--no-package-lock` to `unit` and `integration` rules.
19
+
20
+ * Released `protocol_17` feature flag.
21
+
22
+ * The agent now reacts to failed New Relic requests based on response code, as
23
+ opposed to parsing an exception message in the response body.
24
+
25
+ * Replaced `nsp` with `npm audit` in security checks.
26
+
27
+ * Collector now specify `application/json` content-type when data is compressed
28
+ instead of `octet-stream`.
29
+
30
+ * Bumped ecmaVersion in test .eslintrc to 8
31
+
32
+ ### 4.12.0 (2018-12-03):
33
+
34
+ * Converted error handling in `CollectorAPI` and `RemoteMethod` to callbacks.
35
+
36
+ Previously many of the errors were thrown. For consistency with async errors,
37
+ these are now handed to the callback instead of thrown. The old behavior could
38
+ result in a crash under a few circumstances, such as when the agent exceeded a
39
+ configured maximum payload size. These errors came from `RemoteMethod._safeRequest`.
40
+ Since these errors are handed to the callback instead of thrown, this bug is no
41
+ longer a potential.
42
+
43
+ * Added IP address collection and forwarding of metadata headers for upcoming
44
+ protocol 17.
45
+
46
+ These features are currently behind the `protocol_17` feature flag until all
47
+ parts of protocol 17 are implemented.
48
+
49
+ * Refactored harvest interactions in preparation for protocol 17 status codes.
50
+
51
+ ### 4.11.0 (2018-11-15):
52
+
53
+ * Changed totalTime attribute to be in decimal seconds instead of milliseconds for
54
+ transaction events.
55
+
56
+ * Agent no longer produces spans on ignored transactions.
57
+
58
+ Previously, the agent would produce distributed tracing span events regardless
59
+ of the ignored status of the transaction the events originated from.
60
+
61
+ * Extended Restify instrumentation to mark possible transaction names in order to
62
+ account for async response methods.
63
+
64
+ * Added `protocol_17` feature flag.
65
+
66
+ Flag will be removed and protocol will be hard-coded to `17` once functionality
67
+ is released on New Relic backend.
68
+
69
+ * Added switch statement indenting standard to eslintrc
70
+
71
+ * This release also includes changes to the agent to enable monitoring of Lambda
72
+ functions. If you are interested in learning more or previewing New Relic Lambda
73
+ monitoring please email lambda_preview@newrelic.com.
74
+
75
+ * Introduced "warn" level 2 space rule to eslintrc
76
+
77
+ * Updated `hapi@16` versioned tests to only run on Node 6 and above.
78
+
79
+ * Upgraded `@newrelic/test-utilities` to v2.
80
+
81
+ * Pinned mysql2 to `<1.6.2` in versioned tests.
82
+
83
+ * Added `waitForIdle` option to `API#shutdown`.
84
+
85
+ This new option will make the agent wait for all active transactions to finish
86
+ before actually shutting down. This does not pre-empt creation of new transactions,
87
+ so care must be taken to ensure the active transaction pool drains or the agent
88
+ will never shut down.
89
+
1
90
  ### 4.10.0 (2018-11-01):
2
91
 
3
92
  * Added `DatastoreShim#getDatabaseNameFromUseQuery`
package/api.js CHANGED
@@ -1,21 +1,22 @@
1
1
  'use strict'
2
2
 
3
- var arity = require('./lib/util/arity')
4
- var util = require('util')
5
- var logger = require('./lib/logger').child({component: 'api'})
6
- var NAMES = require('./lib/metrics/names')
7
- var recordWeb = require('./lib/metrics/recorders/http')
8
- var recordBackground = require('./lib/metrics/recorders/other')
9
- var customRecorder = require('./lib/metrics/recorders/custom')
10
- var hashes = require('./lib/util/hashes')
11
- var properties = require('./lib/util/properties')
12
- var stringify = require('json-stringify-safe')
13
- var shimmer = require('./lib/shimmer')
14
- var Shim = require('./lib/shim/shim')
15
- var TransactionHandle = require('./lib/transaction/handle')
16
-
17
- const DESTS = require('./lib/config/attribute-filter').DESTINATIONS
3
+ const arity = require('./lib/util/arity')
4
+ const util = require('util')
5
+ const logger = require('./lib/logger').child({component: 'api'})
6
+ const recordWeb = require('./lib/metrics/recorders/http')
7
+ const recordBackground = require('./lib/metrics/recorders/other')
8
+ const customRecorder = require('./lib/metrics/recorders/custom')
9
+ const hashes = require('./lib/util/hashes')
10
+ const properties = require('./lib/util/properties')
11
+ const stringify = require('json-stringify-safe')
12
+ const shimmer = require('./lib/shimmer')
13
+ const TransactionShim = require('./lib/shim/transaction-shim')
14
+ const TransactionHandle = require('./lib/transaction/handle')
15
+ const AwsLambda = require('./lib/serverless/aws-lambda')
16
+
17
+ const ATTR_DEST = require('./lib/config/attribute-filter').DESTINATIONS
18
18
  const MODULE_TYPE = require('./lib/shim/constants').MODULE_TYPE
19
+ const NAMES = require('./lib/metrics/names')
19
20
 
20
21
  /*
21
22
  *
@@ -55,7 +56,8 @@ const CUSTOM_EVENT_TYPE_REGEX = /^[a-zA-Z0-9:_ ]+$/
55
56
  */
56
57
  function API(agent) {
57
58
  this.agent = agent
58
- this.shim = new Shim(agent, 'NewRelicAPI')
59
+ this.shim = new TransactionShim(agent, 'NewRelicAPI')
60
+ this.awsLambda = new AwsLambda(agent)
59
61
  }
60
62
 
61
63
  /**
@@ -83,8 +85,10 @@ API.prototype.setTransactionName = function setTransactionName(name) {
83
85
 
84
86
  if (!name) {
85
87
  if (transaction && transaction.url) {
86
- logger.error("Must include name in setTransactionName call for URL %s.",
87
- transaction.url)
88
+ logger.error(
89
+ "Must include name in setTransactionName call for URL %s.",
90
+ transaction.url
91
+ )
88
92
  } else {
89
93
  logger.error("Must include name in setTransactionName call.")
90
94
  }
@@ -191,8 +195,10 @@ API.prototype.setControllerName = function setControllerName(name, action) {
191
195
 
192
196
  if (!name) {
193
197
  if (transaction && transaction.url) {
194
- logger.error("Must include name in setControllerName call for URL %s.",
195
- transaction.url)
198
+ logger.error(
199
+ "Must include name in setControllerName call for URL %s.",
200
+ transaction.url
201
+ )
196
202
  } else {
197
203
  logger.error("Must include name in setControllerName call.")
198
204
  }
@@ -623,12 +629,12 @@ API.prototype.getBrowserTimingHeader = function getBrowserTimingHeader(options)
623
629
 
624
630
  var attrs = Object.create(null)
625
631
 
626
- const customAttrs = trans.trace.custom.get(DESTS.BROWSER_EVENT)
632
+ const customAttrs = trans.trace.custom.get(ATTR_DEST.BROWSER_EVENT)
627
633
  if (!properties.isEmpty(customAttrs)) {
628
634
  attrs.u = customAttrs
629
635
  }
630
636
 
631
- const agentAttrs = trans.trace.attributes.get(DESTS.BROWSER_EVENT)
637
+ const agentAttrs = trans.trace.attributes.get(ATTR_DEST.BROWSER_EVENT)
632
638
  if (!properties.isEmpty(agentAttrs)) {
633
639
  attrs.a = agentAttrs
634
640
  }
@@ -1567,33 +1573,59 @@ function instrumentMessages(moduleName, onRequire, onError) {
1567
1573
  /**
1568
1574
  * Shuts down the agent.
1569
1575
  *
1570
- * @param {object} [options] object with shut down options
1571
- * @param {boolean} [options.collectPendingData=false] If true, the agent will send any
1572
- * pending data to the collector
1573
- * before shutting down.
1574
- * @param {number} [options.timeout] time in ms to wait before
1575
- * shutting down
1576
- * @param {function} [callback] callback function that runs when
1577
- * agent stopped
1576
+ * @param {object} [options]
1577
+ * Object with shut down options.
1578
+ *
1579
+ * @param {boolean} [options.collectPendingData=false]
1580
+ * If true, the agent will send any pending data to the collector before
1581
+ * shutting down.
1582
+ *
1583
+ * @param {number} [options.timeout=0]
1584
+ * Time in milliseconds to wait before shutting down.
1585
+ *
1586
+ * @param {boolean} [options.waitForIdle=false]
1587
+ * If true, the agent will not shut down until there are no active transactions.
1588
+ *
1589
+ * @param {function} [callback]
1590
+ * Callback function that runs when agent stops.
1578
1591
  */
1579
1592
  API.prototype.shutdown = function shutdown(options, cb) {
1580
- var metric = this.agent.metrics.getOrCreateMetric(
1581
- NAMES.SUPPORTABILITY.API + '/shutdown'
1582
- )
1583
- metric.incrementCallCount()
1593
+ this.agent.metrics.getOrCreateMetric(`${NAMES.SUPPORTABILITY.API}/shutdown`)
1594
+ .incrementCallCount()
1584
1595
 
1585
- var callback = cb
1586
- if (!callback) {
1587
- if (typeof options === 'function') {
1588
- callback = options
1589
- } else {
1590
- callback = function noop() {}
1591
- }
1596
+ let callback = cb
1597
+ if (typeof options === 'function') {
1598
+ // shutdown(cb)
1599
+ callback = options
1600
+ options = {}
1601
+ } else if (typeof callback !== 'function') {
1602
+ // shutdown([options])
1603
+ callback = () => {}
1592
1604
  }
1605
+ if (!options) {
1606
+ // shutdown(null, cb)
1607
+ options = {}
1608
+ }
1609
+
1610
+ _doShutdown(this, options, callback)
1611
+ }
1612
+
1613
+ function _doShutdown(api, options, callback) {
1614
+ const agent = api.agent
1593
1615
 
1594
- var agent = this.agent
1616
+ // If we need to wait for idle and there are currently active transactions,
1617
+ // listen for transactions ending and check if we're ready to go.
1618
+ if (options.waitForIdle && agent.activeTransactions) {
1619
+ options.waitForIdle = false // To prevent recursive waiting.
1620
+ agent.on('transactionFinished', function onTransactionFinished() {
1621
+ if (agent.activeTransactions === 0) {
1622
+ setImmediate(_doShutdown, api, options, callback)
1623
+ }
1624
+ })
1625
+ return
1626
+ }
1595
1627
 
1596
- function cb_harvest(error) {
1628
+ function afterHarvest(error) {
1597
1629
  if (error) {
1598
1630
  logger.error(
1599
1631
  error,
@@ -1603,7 +1635,7 @@ API.prototype.shutdown = function shutdown(options, cb) {
1603
1635
  agent.stop(callback)
1604
1636
  }
1605
1637
 
1606
- if (options && options.collectPendingData && agent._state !== 'started') {
1638
+ if (options.collectPendingData && agent._state !== 'started') {
1607
1639
  if (typeof options.timeout === 'number') {
1608
1640
  setTimeout(function shutdownTimeout() {
1609
1641
  agent.stop(callback)
@@ -1616,7 +1648,7 @@ API.prototype.shutdown = function shutdown(options, cb) {
1616
1648
  }
1617
1649
 
1618
1650
  agent.on('started', function shutdownHarvest() {
1619
- agent.harvest(cb_harvest)
1651
+ agent.harvest(afterHarvest)
1620
1652
  })
1621
1653
  agent.on('errored', function logShutdownError(error) {
1622
1654
  agent.stop(callback)
@@ -1627,8 +1659,8 @@ API.prototype.shutdown = function shutdown(options, cb) {
1627
1659
  )
1628
1660
  }
1629
1661
  })
1630
- } else if (options && options.collectPendingData) {
1631
- agent.harvest(cb_harvest)
1662
+ } else if (options.collectPendingData) {
1663
+ agent.harvest(afterHarvest)
1632
1664
  } else {
1633
1665
  agent.stop(callback)
1634
1666
  }
@@ -1653,4 +1685,13 @@ function _checkKeyLength(object, maxLength) {
1653
1685
  return badKey
1654
1686
  }
1655
1687
 
1688
+ API.prototype.setLambdaHandler = function setLambdaHandler(handler) {
1689
+ const metric = this.agent.metrics.getOrCreateMetric(
1690
+ NAMES.SUPPORTABILITY.API + '/setLambdaHandler'
1691
+ )
1692
+ metric.incrementCallCount()
1693
+
1694
+ return this.awsLambda.patchLambdaHandler(handler)
1695
+ }
1696
+
1656
1697
  module.exports = API
@@ -31,8 +31,11 @@ if [ "$SUITE" = "versioned" ]; then
31
31
  # npm 2 has an issue installing correctly for the superagent versioned tests.
32
32
  # TODO: Remove this check when deprecating Node <5.
33
33
  if [ "$(get_version npm)" == "2" ]; then
34
- echo " -- upgrading npm --- "
34
+ echo " -- upgrading npm to 3 --- "
35
35
  npm install -g npm@3
36
+ elif [ "$(get_version npm)" == "5" ]; then
37
+ echo " --- upgrading npm to 6 --- "
38
+ npm install -g npm@6
36
39
  else
37
40
  echo " --- not upgrading npm ($(npm --version)) --- "
38
41
  fi
@@ -45,14 +48,19 @@ if [ "$SUITE" = "versioned" ]; then
45
48
  ./bin/travis-install-mongo.sh > /dev/null
46
49
 
47
50
  echo " --- done installing $SUITE requirements --- "
51
+
52
+ elif [ "$SUITE" = "security" ]; then
53
+ # npm 6 has the `audit` command used for security check.
54
+ if [ "$(get_version npm)" != "6" ]; then
55
+ echo " -- upgrading npm to 6 --- "
56
+ npm install -g npm@6
57
+ else
58
+ echo " --- not upgrading npm ($(npm --version)) --- "
59
+ fi
48
60
  else
49
- echo " --- not installing $SUITE requirements --- "
61
+ echo " --- no $SUITE installation requirements --- "
50
62
  fi
51
63
 
52
- if [ "$SUITE" = "security" ]; then
53
- echo " --- installing nsp --- "
54
- npm install --no-save nsp
55
- fi
56
64
 
57
65
  # Always install time.
58
66
  sudo apt-get install -qq time
package/index.js CHANGED
@@ -144,18 +144,20 @@ function createAgent(config) {
144
144
  var uninstrumented = require('./lib/uninstrumented')
145
145
  uninstrumented.check(shimmer.registeredInstrumentations)
146
146
 
147
- agent.start(function cb_start(error) {
148
- if (!error) {
149
- return logger.debug("New Relic for Node.js is connected to New Relic.")
150
- }
147
+ agent.start(function afterStart(error) {
148
+ if (error) {
149
+ var errorMessage = 'New Relic for Node.js halted startup due to an error:'
150
+ logger.error(error, errorMessage)
151
151
 
152
- var errorMessage = "New Relic for Node.js halted startup due to an error:"
153
- logger.error(error, errorMessage)
152
+ /* eslint-disable no-console */
153
+ console.error(errorMessage)
154
+ console.error(error.stack)
155
+ /* eslint-enable no-console */
154
156
 
155
- /* eslint-disable no-console */
156
- console.error(errorMessage)
157
- console.error(error.stack)
158
- /* eslint-enable no-console */
157
+ return
158
+ }
159
+
160
+ logger.debug('New Relic for Node.js is connected to New Relic.')
159
161
  })
160
162
 
161
163
  return agent
@@ -2,6 +2,7 @@
2
2
 
3
3
  class AdaptiveSampler {
4
4
  constructor(opts) {
5
+ this._serverless = opts.serverless
5
6
  this._seen = 0
6
7
  this._sampled = 0
7
8
  this._samplingPeriod = 0
@@ -12,6 +13,11 @@ class AdaptiveSampler {
12
13
  this._resetInterval = null
13
14
 
14
15
  this.samplingPeriod = opts.period
16
+
17
+ if (this._serverless) {
18
+ this._windowStart = null
19
+ opts.agent.on('transactionStarted', this.maybeUpdateWindow.bind(this))
20
+ }
15
21
  }
16
22
 
17
23
  get sampled() {
@@ -37,17 +43,34 @@ class AdaptiveSampler {
37
43
  }
38
44
 
39
45
  set samplingPeriod(period) {
40
- clearInterval(this._resetInterval)
41
46
  this._samplingPeriod = period
47
+ if (!this._serverless) {
48
+ clearInterval(this._resetInterval)
42
49
 
43
- if (period) {
44
- this._resetInterval = setInterval(() => this._reset(), period)
45
- this._resetInterval.unref()
50
+ if (period) {
51
+ this._resetInterval = setInterval(() => this._reset(), period)
52
+ this._resetInterval.unref()
53
+ }
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Used to determine if the sampling window should be reset based on the start time
59
+ * of the provided transaction.
60
+ *
61
+ * @param {object} transaction - The transaction to compare against the current
62
+ * window.
63
+ */
64
+ maybeUpdateWindow(transaction) {
65
+ const timestamp = transaction.timer.start
66
+ if (!this._windowStart || timestamp - this._windowStart >= this._samplingPeriod) {
67
+ this._windowStart = timestamp
68
+ this._reset()
46
69
  }
47
70
  }
48
71
 
49
72
  /**
50
- * Determins if an object should be sampled based on the object's priority and
73
+ * Determines if an object should be sampled based on the object's priority and
51
74
  * the number of objects sampled in this window.
52
75
  *
53
76
  * @param {object} obj - The object to check for sampleability.