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 +0 -10
- package/Migration Guide.md +12 -0
- package/NEWS.md +65 -0
- package/README.md +9 -7
- package/api.js +76 -2
- package/bin/run-versioned-tests.sh +7 -4
- package/index.js +3 -3
- package/lib/instrumentation/core/http.js +6 -1
- package/lib/instrumentation/hapi.js +4 -0
- package/lib/instrumentations.js +25 -21
- package/lib/shim/datastore-shim.js +3 -0
- package/lib/shim/shim.js +9 -1
- package/lib/shimmer.js +17 -31
- package/lib/transaction/trace/attributes.js +13 -1
- package/lib/uninstrumented.js +7 -1
- package/package.json +6 -4
- package/stub_api.js +15 -1
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"
|
package/Migration Guide.md
CHANGED
|
@@ -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.
|
|
711
|
+
#### newrelic.startSegment(name, record, handler, callback)
|
|
712
712
|
|
|
713
|
-
`name` is the name of the
|
|
714
|
-
|
|
715
|
-
|
|
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 `
|
|
718
|
-
|
|
719
|
-
|
|
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
|
-
|
|
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
|
-
* @
|
|
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
|
-
|
|
12
|
+
directories=()
|
|
13
13
|
if [[ "$1" != '' ]]; then
|
|
14
|
-
|
|
14
|
+
directories=(
|
|
15
|
+
"test/versioned/${1}"
|
|
16
|
+
"node_modules/@newrelic/${1}/tests/versioned"
|
|
17
|
+
)
|
|
15
18
|
fi
|
|
16
19
|
|
|
17
|
-
export
|
|
18
|
-
time ./node_modules/.bin/versioned-tests $VERSIONED_MODE -i 2 $
|
|
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
|
|
46
|
-
if (psemver.satisfies('<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.
|
|
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
|
-
|
|
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(
|
package/lib/instrumentations.js
CHANGED
|
@@ -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
|
-
'
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
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
|
|
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
|
|
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
|
-
|
|
384
|
-
var
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
+
}
|
package/lib/uninstrumented.js
CHANGED
|
@@ -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
|
+
"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.
|
|
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": "^
|
|
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": "
|
|
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 =
|
|
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') {
|