newrelic 2.0.0 → 2.2.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.
Files changed (44) hide show
  1. package/.eslintrc +1 -0
  2. package/.github/PULL_REQUEST_TEMPLATE.md +5 -0
  3. package/NEWS.md +75 -0
  4. package/README.md +24 -12
  5. package/api.js +74 -29
  6. package/index.js +6 -2
  7. package/lib/agent.js +15 -3
  8. package/lib/collector/api.js +11 -9
  9. package/lib/collector/facts.js +9 -9
  10. package/lib/config.default.js +24 -2
  11. package/lib/config.js +70 -7
  12. package/lib/db/parse-sql.js +3 -0
  13. package/lib/db/tracer.js +3 -3
  14. package/lib/feature_flags.js +1 -0
  15. package/lib/instrumentation/core/async_hooks.js +92 -0
  16. package/lib/instrumentation/core/child_process.js +35 -0
  17. package/lib/instrumentation/core/globals.js +4 -23
  18. package/lib/instrumentation/core/http.js +1 -1
  19. package/lib/instrumentation/hapi.js +67 -33
  20. package/lib/instrumentation/ioredis.js +1 -6
  21. package/lib/metrics/names.js +7 -2
  22. package/lib/shim/datastore-shim.js +13 -1
  23. package/lib/shim/shim.js +46 -8
  24. package/lib/shim/webframework-shim.js +4 -2
  25. package/lib/stats/index.js +1 -1
  26. package/lib/system-info.js +21 -42
  27. package/lib/transaction/handle.js +14 -0
  28. package/lib/transaction/index.js +10 -2
  29. package/lib/transaction/tracer/index.js +1 -0
  30. package/lib/util/hashes.js +8 -1
  31. package/lib/util/logger.js +4 -4
  32. package/lib/util/sql/obfuscate.js +10 -4
  33. package/lib/utilization/aws-info.js +46 -0
  34. package/lib/utilization/azure-info.js +54 -0
  35. package/lib/utilization/common.js +106 -0
  36. package/lib/utilization/docker-info.js +100 -0
  37. package/lib/utilization/gcp-info.js +56 -0
  38. package/lib/utilization/index.js +28 -0
  39. package/lib/utilization/pcf-info.js +38 -0
  40. package/newrelic.js +1 -2
  41. package/package.json +2 -1
  42. package/stub_api.js +26 -9
  43. package/lib/aws-info.js +0 -100
  44. package/lib/parse-dockerinfo.js +0 -57
package/.eslintrc CHANGED
@@ -4,6 +4,7 @@
4
4
  "browser": false
5
5
  },
6
6
  "globals": {
7
+ "Map": true,
7
8
  "Promise": true
8
9
  },
9
10
  "rules": {
@@ -0,0 +1,5 @@
1
+ ## CHANGE LOG
2
+
3
+ ## INTERNAL LINKS
4
+
5
+ ## NOTES
package/NEWS.md CHANGED
@@ -1,4 +1,79 @@
1
1
 
2
+ ### v2.2.0 (2017-08-22):
3
+ * Added support for ignoring ranges of status codes.
4
+
5
+ The configuration `error_collector.ignore_status_codes` can now take ranges
6
+ of numbers. For example, `ignore_status_codes: ['400-404']` would ignore 400,
7
+ 401, 402, 403, and 404.
8
+
9
+ * Fixed a bug when a custom collector port was provided in the configuration
10
+ that prevented redirected connections from working.
11
+
12
+ * Fixed a bug in `Shim#record` that could cause an exception when trying to
13
+ create a new segment as part of an ended/inactive transaction.
14
+
15
+ * Fixed issue with custom Hapi handlers causing an error.
16
+
17
+ Previously custom Hapi handlers defined using the `server.handler()` method
18
+ were causing the Hapi server to return a 500 error. Now they are correctly
19
+ handled and recorded as middleware functions.
20
+
21
+ * Transaction state is now maintained in `ChildProcess` event listeners.
22
+
23
+ * Updated examples and documentation regarding custom transaction creation.
24
+
25
+ All examples and documentation now point at the `newrelic.start*Transaction`
26
+ methods.
27
+
28
+ * Reducing logging verbosity in the SQL query obfuscator.
29
+
30
+ * Experimental instrumentation for `async/await`
31
+
32
+ This is experimental instrumentation and has not yet been tested in a wide
33
+ array of production environments. The feature is currently off by default
34
+ behind a feature flag. To enable this experimental instrumentation, add
35
+ `await_support: true` to the `feature_flag` setting in your agent config
36
+ file.
37
+
38
+ ### v2.1.0 (2017-08-08):
39
+ * Improved metadata collection for AWS, Azure, GCE, and Pivotal Cloud Foundry.
40
+
41
+ * Fixed a bug in PG query obfuscation for `$` placeholders.
42
+
43
+ The agent used to mis-detect `$1` value placeholders as unmatched
44
+ dollar-quoted strings causing the whole query to be obfuscated to just `?`.
45
+ These placeholders are now correctly detected and obfuscated.
46
+
47
+ ### v2.0.2 (2017-08-01):
48
+ * Improved documentation for `newrelic.start*Transaction` and `TransactionHandle.`
49
+
50
+ Formatting for the `startWebTransaction` and `startBackgroundTransaction`
51
+ methods was fixed and documentation for the `TransactionHandle` class which
52
+ `getTransaction` returns was added.
53
+
54
+ * Fixed parsing the table name from SQL queries.
55
+
56
+ Quotes around the table name are now stripped after parsing the query and
57
+ before constructing the metrics.
58
+
59
+ * Fixed unhandled rejection error caused by `ioredis` instrumentation.
60
+
61
+ ### v2.0.1 (2017-07-25):
62
+ * Fixed issue with transaction events not including correct duration values.
63
+
64
+ This issue was introduced in v2.0.0, and it has affected web transactions histogram
65
+ and percentile charts.
66
+
67
+ * Fixed issue with Redis instrumentation causing the agent to crash in some cases.
68
+
69
+ Previously, the Redis instrumentation would crash the agent when Redis commands were
70
+ called without a callback and after the transaction has ended.
71
+
72
+ * Fixed issue with the agent crashing on Node v4.0-4.4 and v5.0-5.9.
73
+
74
+ This issue was caused by incorrect shim for Buffer.from(), and it affected older minor
75
+ versions of Node v4 and v5.
76
+
2
77
  ### v2.0.0 (2017-07-17):
3
78
  * [The New Relic Node Agent v2 is here!](https://blog.newrelic.com/2017/07/18/nodejs-agent-v2-api/)
4
79
 
package/README.md CHANGED
@@ -656,7 +656,7 @@ application, the agent can't tell when they should begin and end.
656
656
  Read more at:
657
657
  https://docs.newrelic.com/docs/agents/nodejs-agent/supported-features/nodejs-custom-instrumentation
658
658
 
659
- #### newrelic.createWebTransaction(url, handle)
659
+ #### newrelic.startWebTransaction(url, handle)
660
660
 
661
661
  `url` is the name of the web transaction. It should be pretty static, not
662
662
  including anything like user ids or any other data that is very specific to the
@@ -669,16 +669,22 @@ called within an active background transaction, it will create a new,
669
669
  independent transaction and any calls within the `handle` will be bound to the
670
670
  new web transaction.
671
671
 
672
- Custom transactions **must** be ended manually by calling `endTransaction()`.
673
- Timing for custom transaction starts from when the returned wrapped function is
674
- called until `endTransaction()` is called.
672
+ Custom transactions can be ended within the `handle` in one of three ways:
675
673
 
676
- #### newrelic.createBackgroundTransaction(name, [group], handle)
674
+ 1. Call `transaction.end()`. The `transaction` can be received by calling
675
+ `newrelic.getTransaction()` first thing in the handler function. Then,
676
+ when you call `transaction.end()` timing will stop.
677
+ 2. Return a promise. The transaction will end when the promise resolves or
678
+ rejects.
679
+ 3. Do neither. If no promise is returned, and `getTransaction()` isn't
680
+ called, the transaction will end immediately after the handle returns.
681
+
682
+ #### newrelic.startBackgroundTransaction(name [, group], handle)
677
683
 
678
684
  `name` is the name of the job. It should be pretty static, and not include job
679
685
  ids or anything very specific to that run of the job. `group` is optional, and
680
686
  allows you to group types of jobs together. This should follow similar rules as
681
- the `name`. `handle` is a function that encompases your background job. Both
687
+ the `name`. `handle` is a function that encompasses your background job. Both
682
688
  custom and auto instrumentation will be captured as part of the transaction.
683
689
 
684
690
  If called within an active background transaction, it will act as a nested
@@ -686,14 +692,20 @@ tracer. If called within an active web transaction, it will create a new
686
692
  transaction and any calls within the `handle` will be bound to the new,
687
693
  independent background transaction.
688
694
 
689
- Custom transactions **must** be ended manually by calling `endTransaction()`.
690
- Timing for custom transaction starts from when the returned wrapped function is
691
- called until `endTransaction()` is called.
695
+ 1. Call `transaction.end()`. The `transaction` can be received by calling
696
+ `newrelic.getTransaction()` first thing in the handler function. Then,
697
+ when you call `transaction.end()` timing will stop.
698
+ 2. Return a promise. The transaction will end when the promise resolves or
699
+ rejects.
700
+ 3. Do neither. If no promise is returned, and `getTransaction()` isn't
701
+ called, the transaction will end immediately after the handle returns.
692
702
 
693
- #### newrelic.endTransaction()
703
+ #### newrelic.getTransaction()
694
704
 
695
- This takes no arguments and must be called to end any custom transaction. It
696
- will detect what kind of transaction was active and end it.
705
+ This takes no arguments and returns the currently active transaction. If the
706
+ returned transaction is a custom one, started with either `startWebTransaction`
707
+ or `startBackgroundTransaction`, then `transaction.end()` must be called to
708
+ end the transaction.
697
709
 
698
710
  #### newrelic.createTracer(name, handle)
699
711
 
package/api.js CHANGED
@@ -91,6 +91,7 @@ API.prototype.setTransactionName = function setTransactionName(name) {
91
91
  return
92
92
  }
93
93
 
94
+ logger.trace('Setting transaction %s name to %s', transaction.id, name)
94
95
  transaction.forceName = NAMES.CUSTOM + '/' + name
95
96
  }
96
97
 
@@ -102,7 +103,7 @@ API.prototype.setTransactionName = function setTransactionName(name) {
102
103
  * - ignore: set the transaction that was active when
103
104
  * `API#getTransaction` was called to be ignored.
104
105
  *
105
- * @returns {object} transaction The transaction object with the `end`
106
+ * @returns {TransactionHandle} transaction The transaction object with the `end`
106
107
  * and `ignore` methods on it.
107
108
  */
108
109
  API.prototype.getTransaction = function getTransaction() {
@@ -622,6 +623,15 @@ API.prototype.createTracer = function createTracer(name, callback) {
622
623
  return arity.fixArity(callback, tracer.bindFunction(callback, segment, true))
623
624
  }
624
625
 
626
+ API.prototype.createWebTransaction = util.deprecate(
627
+ createWebTransaction, [
628
+ 'API#createWebTransaction is being deprecated!',
629
+ 'Please use API#startWebTransaction for transaction creation',
630
+ 'and API#getTransaction for transaction management including',
631
+ 'ending transactions.'
632
+ ].join(' ')
633
+ )
634
+
625
635
  /**
626
636
  * Creates a function that represents a web transaction. It does not start the
627
637
  * transaction automatically - the returned function needs to be invoked to start it.
@@ -638,16 +648,11 @@ API.prototype.createTracer = function createTracer(name, callback) {
638
648
  related transactions in APM, so it should be a generic
639
649
  name and not iclude any variable parameters.
640
650
  * @param {Function} handle Function that represents the transaction work.
651
+ *
652
+ * @memberOf API#
653
+ *
654
+ * @deprecated since version 2.0
641
655
  */
642
- API.prototype.createWebTransaction = util.deprecate(
643
- createWebTransaction,
644
- [
645
- 'API#createWebTransaction is being deprecated!',
646
- 'Please use API#startWebTransaction and API#getTransaction',
647
- 'for transaction creation and management.'
648
- ].join(' ')
649
- )
650
-
651
656
  function createWebTransaction(url, handle) {
652
657
  var metric = this.agent.metrics.getOrCreateMetric(
653
658
  NAMES.SUPPORTABILITY.API + '/createWebTransaction'
@@ -710,9 +715,9 @@ function createWebTransaction(url, handle) {
710
715
  * synchronously returns UNLESS:
711
716
  * 1. The handle function returns a promise, where the end of the
712
717
  * transaction will be tied to the end of the promise returned.
713
- * 2. `API#getTransaction` is called in the handle, flagging the
718
+ * 2. {@link API#getTransaction} is called in the handle, flagging the
714
719
  * transaction as externally handled. In this case the transaction
715
- * will be ended when `Transaction#end` is called in the user's code.
720
+ * will be ended when {@link TransactionHandle#end} is called in the user's code.
716
721
  *
717
722
  * @example
718
723
  * var newrelic = require('newrelic')
@@ -731,9 +736,7 @@ function createWebTransaction(url, handle) {
731
736
  * @param {Function} handle
732
737
  * Function that represents the transaction work.
733
738
  */
734
- API.prototype.startWebTransaction = startWebTransaction
735
-
736
- function startWebTransaction(url, handle) {
739
+ API.prototype.startWebTransaction = function startWebTransaction(url, handle) {
737
740
  var metric = this.agent.metrics.getOrCreateMetric(
738
741
  NAMES.SUPPORTABILITY.API + '/startWebTransaction'
739
742
  )
@@ -784,15 +787,17 @@ function startWebTransaction(url, handle) {
784
787
  })()
785
788
  }
786
789
 
790
+ API.prototype.startBackgroundTransaction = startBackgroundTransaction
791
+
787
792
  /**
788
793
  * Creates and starts a background transaction to record work done in
789
794
  * the handle supplied. This transaction will run until the handle
790
795
  * synchronously returns UNLESS:
791
796
  * 1. The handle function returns a promise, where the end of the
792
797
  * transaction will be tied to the end of the promise returned.
793
- * 2. `API#getTransaction` is called in the handle, flagging the
798
+ * 2. {@link API#getTransaction} is called in the handle, flagging the
794
799
  * transaction as externally handled. In this case the transaction
795
- * will be ended when `Transaction#end` is called in the user's code.
800
+ * will be ended when {@link TransactionHandle#end} is called in the user's code.
796
801
  *
797
802
  * @example
798
803
  * var newrelic = require('newrelic')
@@ -816,9 +821,9 @@ function startWebTransaction(url, handle) {
816
821
  *
817
822
  * @param {Function} handle
818
823
  * Function that represents the background work.
824
+ *
825
+ * @memberOf API#
819
826
  */
820
- API.prototype.startBackgroundTransaction = startBackgroundTransaction
821
-
822
827
  function startBackgroundTransaction(name, group, handle) {
823
828
  var metric = this.agent.metrics.getOrCreateMetric(
824
829
  NAMES.SUPPORTABILITY.API + '/startBackgroundTransaction'
@@ -878,6 +883,15 @@ function startBackgroundTransaction(name, group, handle) {
878
883
  })()
879
884
  }
880
885
 
886
+ API.prototype.createBackgroundTransaction = util.deprecate(
887
+ createBackgroundTransaction, [
888
+ 'API#createBackgroundTransaction is being deprecated!',
889
+ 'Please use API#startBackgroundTransaction for transaction creation',
890
+ 'and API#getTransaction for transaction management including',
891
+ 'ending transactions.'
892
+ ].join(' ')
893
+ )
894
+
881
895
  /**
882
896
  * Creates a function that represents a background transaction. It does not
883
897
  * start the transaction automatically - the returned function needs to be
@@ -908,16 +922,11 @@ function startBackgroundTransaction(name, group, handle) {
908
922
  * @return {Function} The `handle` function wrapped with starting a new
909
923
  * transaction. This function can be called repeatedly to start multiple
910
924
  * transactions.
925
+ *
926
+ * @memberOf API#
927
+ *
928
+ * @deprecated since version 2.0
911
929
  */
912
- API.prototype.createBackgroundTransaction = util.deprecate(
913
- createBackgroundTransaction,
914
- [
915
- 'API#createBackgroundTransaction is being deprecated!',
916
- 'Please use API#startBackgroundTransaction and API#getTransaction',
917
- 'for transaction creation and management.'
918
- ].join(' ')
919
- )
920
-
921
930
  function createBackgroundTransaction(name, group, handle) {
922
931
  var metric = this.agent.metrics.getOrCreateMetric(
923
932
  NAMES.SUPPORTABILITY.API + '/createBackgroundTransaction'
@@ -983,6 +992,10 @@ function createBackgroundTransaction(name, group, handle) {
983
992
  return arity.fixArity(handle, proxy)
984
993
  }
985
994
 
995
+ /**
996
+ * End the current web or background custom transaction. This method requires being in
997
+ * the correct transaction context when called.
998
+ */
986
999
  API.prototype.endTransaction = function endTransaction() {
987
1000
  var metric = this.agent.metrics.getOrCreateMetric(
988
1001
  NAMES.SUPPORTABILITY.API + '/endTransaction'
@@ -1011,6 +1024,21 @@ API.prototype.endTransaction = function endTransaction() {
1011
1024
  }
1012
1025
  }
1013
1026
 
1027
+ /**
1028
+ * Record an event-based metric, usually associated with a particular duration.
1029
+ * The `name` must be a string following standard metric naming rules. The `value` will
1030
+ * usually be a number, but it can also be an object.
1031
+ * * When `value` is a numeric value, it should represent the magnitude of a measurement
1032
+ * associated with an event; for example, the duration for a particular method call.
1033
+ * * When `value` is an object, it must contain count, total, min, max, and sumOfSquares
1034
+ * keys, all with number values. This form is useful to aggregate metrics on your own
1035
+ * and report them periodically; for example, from a setInterval. These values will
1036
+ * be aggregated with any previously collected values for the same metric. The names
1037
+ * of these keys match the names of the keys used by the platform API.
1038
+ *
1039
+ * @param {string} name The name of the metric.
1040
+ * @param {number|object} value
1041
+ */
1014
1042
  API.prototype.recordMetric = function recordMetric(name, value) {
1015
1043
  var supportMetric = this.agent.metrics.getOrCreateMetric(
1016
1044
  NAMES.SUPPORTABILITY.API + '/recordMetric'
@@ -1045,7 +1073,7 @@ API.prototype.recordMetric = function recordMetric(name, value) {
1045
1073
 
1046
1074
  for (var i = 0, l = required.length; i < l; ++i) {
1047
1075
  if (typeof value[required[i]] !== 'number') {
1048
- logger.warn('Metric object must include ' + required[i] + ' as a number')
1076
+ logger.warn('Metric object must include %s as a number', required[i])
1049
1077
  return
1050
1078
  }
1051
1079
 
@@ -1062,6 +1090,14 @@ API.prototype.recordMetric = function recordMetric(name, value) {
1062
1090
  metric.merge(stats)
1063
1091
  }
1064
1092
 
1093
+ /**
1094
+ * Update a metric that acts as a simple counter. The count of the selected metric will
1095
+ * be incremented by the specified amount, defaulting to 1.
1096
+ *
1097
+ * @param {string} name The name of the metric.
1098
+ * @param {number} [value] The amount that the count of the metric should be incremented
1099
+ * by.
1100
+ */
1065
1101
  API.prototype.incrementMetric = function incrementMetric(name, value) {
1066
1102
  var metric = this.agent.metrics.getOrCreateMetric(
1067
1103
  NAMES.SUPPORTABILITY.API + '/incrementMetric'
@@ -1091,6 +1127,15 @@ API.prototype.incrementMetric = function incrementMetric(name, value) {
1091
1127
  })
1092
1128
  }
1093
1129
 
1130
+ /**
1131
+ * Record an event-based metric, usually associated with a particular duration.
1132
+ *
1133
+ * @param {string} eventType The name of the event. It must be an alphanumeric string
1134
+ * less than 255 characters.
1135
+ * @param {object} attributes Object of key and value pairs. The keys must be shorter
1136
+ * than 255 characters, and the values must be string, number,
1137
+ * or boolean.
1138
+ */
1094
1139
  API.prototype.recordCustomEvent = function recordCustomEvent(eventType, attributes) {
1095
1140
  var metric = this.agent.metrics.getOrCreateMetric(
1096
1141
  NAMES.SUPPORTABILITY.API + '/recordCustomEvent'
package/index.js CHANGED
@@ -17,6 +17,9 @@ if (require.cache.__NR_cache) {
17
17
  'Attempting to load a second copy of newrelic from %s, using cache instead',
18
18
  __dirname
19
19
  )
20
+ if (require.cache.__NR_cache.agent) {
21
+ require.cache.__NR_cache.agent.recordSupportability('Agent/DoubleLoad')
22
+ }
20
23
  module.exports = require.cache.__NR_cache
21
24
  } else {
22
25
  initialize()
@@ -88,9 +91,10 @@ function initialize() {
88
91
  agent.start(function cb_start(error) {
89
92
  if (!error) {
90
93
  // TODO: After deprecating Node 0.10 and 0.12, simplify this regex.
94
+ // TODO: As new versions come out, make sure to update Angler metrics.
91
95
  var nodeMajor = /^v?((?:0\.)?\d+)/.exec(process.version)
92
- agent.metrics.getOrCreateMetric(
93
- 'Supportability/Nodejs/Version/' + ((nodeMajor && nodeMajor[1]) || 'unknown')
96
+ agent.recordSupportability(
97
+ 'Version/' + ((nodeMajor && nodeMajor[1]) || 'unknown')
94
98
  )
95
99
 
96
100
  return logger.debug("New Relic for Node.js is connected to New Relic.")
package/lib/agent.js CHANGED
@@ -107,6 +107,7 @@ function Agent(config) {
107
107
  this.segmentsCreatedInHarvest = 0
108
108
  this.segmentsClearedInHarvest = 0
109
109
  this.activeTransactions = 0
110
+ this.transactionCreatedInHarvest = 0
110
111
 
111
112
  // Hidden class optimizations.
112
113
  this.harvesterHandle = null
@@ -286,9 +287,11 @@ Agent.prototype.harvest = function harvest(callback) {
286
287
  harvestCleared: this.segmentsClearedInHarvest,
287
288
  activeTransactions: this.activeTransactions
288
289
  }, 'Entity stats on harvest')
290
+ this.recordSupportability('Transactions/Created', this.transactionCreatedInHarvest)
289
291
 
290
292
  this.segmentsCreatedInHarvest = 0
291
293
  this.segmentsClearedInHarvest = 0
294
+ this.transactionCreatedInHarvest = 0
292
295
 
293
296
  if (!this.collector.isConnected()) {
294
297
  return process.nextTick(function cb_nextTick() {
@@ -860,10 +863,10 @@ Agent.prototype._addIntrinsicAttrsFromTransaction = _addIntrinsicAttrsFromTransa
860
863
 
861
864
  function _addIntrinsicAttrsFromTransaction(transaction) {
862
865
  var intrinsicAttributes = {
863
- webDuration: transaction.timer.duration / 1000,
866
+ webDuration: transaction.timer.getDurationInMillis() / 1000,
864
867
  timestamp: transaction.timer.start,
865
868
  name: transaction.name,
866
- duration: transaction.timer.duration / 1000,
869
+ duration: transaction.timer.getDurationInMillis() / 1000,
867
870
  type: 'Transaction',
868
871
  error: transaction.hasErrors()
869
872
  }
@@ -994,7 +997,7 @@ Agent.prototype._transactionFinished = function _transactionFinished(transaction
994
997
  logger.debug('Ignoring %s (%s).', transaction.name, transaction.id)
995
998
  }
996
999
 
997
- this.activeTransactions--
1000
+ --this.activeTransactions
998
1001
  this.totalActiveSegments -= transaction.numSegments
999
1002
  this.segmentsClearedInHarvest += transaction.numSegments
1000
1003
  }
@@ -1008,4 +1011,13 @@ Agent.prototype.getTransaction = function getTransaction() {
1008
1011
  return this.tracer.getTransaction()
1009
1012
  }
1010
1013
 
1014
+ Agent.prototype.recordSupportability = function recordSupportability(name, value) {
1015
+ var metric = this.metrics.getOrCreateMetric(NAMES.SUPPORTABILITY.NODEJS + '/' + name)
1016
+ if (value != null) {
1017
+ metric.recordValue(value)
1018
+ } else {
1019
+ metric.incrementCallCount()
1020
+ }
1021
+ }
1022
+
1011
1023
  module.exports = Agent
@@ -42,11 +42,11 @@ var HTTP_LOL_COLLECTOR = 503
42
42
  function dumpErrors(errors, name) {
43
43
  var index = 1
44
44
 
45
- errors.forEach(function cb_forEach(error) {
45
+ errors.forEach(function forEachError(error) {
46
46
  logger.trace(error, "Error %s during %s:", index++, name)
47
47
 
48
48
  if (error.laterErrors) {
49
- error.laterErrors.forEach(function cb_forEach(laterError) {
49
+ error.laterErrors.forEach(function forEachLaterError(laterError) {
50
50
  logger.trace(laterError, "Error %s during %s:", index++, name)
51
51
  })
52
52
  }
@@ -115,7 +115,7 @@ CollectorAPI.prototype.connect = function connect(callback) {
115
115
  var id = setTimeout(function again() {
116
116
  api._login(retry)
117
117
  }, backoff.interval * TO_MILLIS)
118
-
118
+
119
119
  if (id.unref) {
120
120
  id.unref()
121
121
  }
@@ -129,7 +129,7 @@ CollectorAPI.prototype._login = function _login(callback) {
129
129
  var agent = this._agent
130
130
 
131
131
 
132
- methods.redirect.invoke(null, function cb_invoke(error, collector, body) {
132
+ methods.redirect.invoke(null, function redirectCb(error, collector, body) {
133
133
  if (error) return callback(error, collector, body)
134
134
  if (!collector) {
135
135
  logger.error(
@@ -152,18 +152,20 @@ CollectorAPI.prototype._login = function _login(callback) {
152
152
  )
153
153
 
154
154
  agent.config.host = parts[0]
155
- if (parts.length > 1) {
156
- agent.config.port = parts[1]
157
- }
155
+ agent.config.port = parts[1] || (agent.config.ssl ? 443 : 80)
158
156
  }
159
157
  }
160
158
 
159
+ _getFacts()
160
+ })
161
+
162
+ function _getFacts() {
161
163
  facts(agent, function getEnvDict(environmentDict) {
162
164
  // The collector really likes arrays.
163
165
  // In fact, it kind of insists on them.
164
166
  var environment = [environmentDict]
165
167
 
166
- methods.handshake.invoke(environment, function cb_invoke(error, config, body) {
168
+ methods.handshake.invoke(environment, function handshakeCb(error, config, body) {
167
169
  if (error) return callback(error, config, body)
168
170
  if (!config || !config.agent_run_id) {
169
171
  return callback(new Error("No agent run ID received from handshake."), config)
@@ -183,7 +185,7 @@ CollectorAPI.prototype._login = function _login(callback) {
183
185
  callback(null, config, body)
184
186
  })
185
187
  })
186
- })
188
+ }
187
189
  }
188
190
 
189
191
  /**
@@ -10,7 +10,7 @@ function facts(agent, callback) {
10
10
  var hostname = agent.config.getHostnameSafe()
11
11
  var results = {
12
12
  utilization: {
13
- metadata_version: 2,
13
+ metadata_version: 3,
14
14
  logical_processors: systemInfo.logicalProcessors,
15
15
  total_ram_mib: systemInfo.memory,
16
16
  hostname: hostname
@@ -36,18 +36,18 @@ function facts(agent, callback) {
36
36
  results.app_name.concat([]).sort().join(',')
37
37
  ].join(':')
38
38
 
39
- if (systemInfo.aws || systemInfo.docker) {
40
- results.utilization.vendors = {}
41
- if (systemInfo.aws) {
42
- results.utilization.vendors.aws = systemInfo.aws
43
- }
44
- if (systemInfo.docker) {
45
- results.utilization.vendors.docker = systemInfo.docker
46
- }
39
+ if (systemInfo.bootId) {
40
+ results.utilization.boot_id = systemInfo.bootId
47
41
  }
42
+
43
+ if (systemInfo.vendors) {
44
+ results.utilization.vendors = systemInfo.vendors
45
+ }
46
+
48
47
  if (systemInfo.config) {
49
48
  results.utilization.config = systemInfo.config
50
49
  }
50
+
51
51
  return callback(results)
52
52
  })
53
53
  }
@@ -245,12 +245,34 @@ exports.config = {
245
245
  */
246
246
  detect_aws: true,
247
247
  /**
248
- * This flag dictates whether the agent attempts to reach out to AWS
248
+ * This flag dictates whether the agent attempts to detect if the
249
+ * the process is running on Pivotal Cloud Foundary.
250
+ *
251
+ * @env NEW_RELIC_UTILIZATION_DETECT_PCF
252
+ */
253
+ detect_pcf: true,
254
+ /**
255
+ * This flag dictates whether the agent attempts to reach out to Azure to
256
+ * get info about the vm the process is running on.
257
+ *
258
+ * @env NEW_RELIC_UTILIZATION_DETECT_AZURE
259
+ */
260
+ detect_azure: true,
261
+ /**
262
+ * This flag dictates whether the agent attempts to read files
249
263
  * to get info about the container the process is running in.
250
264
  *
251
265
  * @env NEW_RELIC_UTILIZATION_DETECT_DOCKER
252
266
  */
253
- detect_docker: true
267
+ detect_docker: true,
268
+
269
+ /**
270
+ * This flag dictates whether the agent attempts to reach out to GCP
271
+ * to get info about the vm the process is running on.
272
+ *
273
+ * @env NEW_RELIC_UTILIZATION_DETECT_GCP
274
+ */
275
+ detect_gcp: true
254
276
  },
255
277
  transaction_tracer: {
256
278
  /**