newrelic 7.1.2 → 7.3.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/NEWS.md +97 -0
- package/THIRD_PARTY_NOTICES.md +33 -2
- package/bin/test-naming-rules.js +4 -4
- package/index.js +4 -2
- package/lib/agent.js +4 -0
- package/lib/collector/api.js +45 -18
- package/lib/collector/facts.js +22 -8
- package/lib/collector/http-agents.js +20 -7
- package/lib/collector/remote-method.js +32 -9
- package/lib/config/index.js +48 -39
- package/lib/feature_flags.js +6 -2
- package/lib/grpc/connection.js +39 -15
- package/lib/instrumentation/core/async_hooks.js +101 -14
- package/lib/instrumentation/core/http.js +5 -0
- package/lib/instrumentation/core/timers.js +6 -1
- package/lib/metrics/names.js +7 -1
- package/lib/shim/shim.js +6 -1
- package/lib/spans/create-span-event-aggregator.js +1 -0
- package/lib/spans/span-event.js +6 -3
- package/lib/spans/streaming-span-event.js +6 -3
- package/lib/transaction/index.js +36 -0
- package/newrelic.js +1 -1
- package/package.json +19 -7
- package/CONTRIBUTING.md +0 -135
- package/Migration Guide.md +0 -271
- package/ROADMAP_Node.md +0 -24
- package/SECURITY.md +0 -5
- package/THIRD_PARTY_NOTICES_ADDENDUM.md +0 -213
- package/bin/ca-gen.js +0 -91
- package/bin/cassandra-setup.sh +0 -11
- package/bin/check-workflow-run.js +0 -74
- package/bin/clean.sh +0 -18
- package/bin/compare-bench-results.js +0 -172
- package/bin/create-release.js +0 -74
- package/bin/docker-env-vars.sh +0 -15
- package/bin/docker-services.sh +0 -49
- package/bin/generate-release-notes.js +0 -126
- package/bin/github.js +0 -119
- package/bin/publish-docs.sh +0 -16
- package/bin/run-bench.js +0 -137
- package/bin/run-versioned-tests.sh +0 -32
- package/bin/smoke.sh +0 -8
- package/bin/ssl.sh +0 -87
- package/bin/travis-install-gcc5.sh +0 -13
- package/bin/travis-install-mongo.sh +0 -16
- package/bin/travis-node.sh +0 -57
- package/bin/travis-setup.sh +0 -52
- package/bin/update-ca-bundle.sh +0 -20
- package/bin/update-cats.sh +0 -8
- package/bin/update-changelog-version.js +0 -68
- package/jsdoc-conf.json +0 -18
- package/third_party_manifest.json +0 -619
package/lib/grpc/connection.js
CHANGED
|
@@ -14,14 +14,14 @@ const util = require('util')
|
|
|
14
14
|
|
|
15
15
|
const connectionStates = require('./connection/states')
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const PROTO_OPTIONS = {keepCase: true,
|
|
18
18
|
longs: String,
|
|
19
19
|
enums: String,
|
|
20
20
|
defaults: true,
|
|
21
21
|
oneofs: true
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const
|
|
24
|
+
const PROTO_DEFINITION_PATH = __dirname +
|
|
25
25
|
'../../../lib/grpc/endpoints/infinite-tracing/v1.proto'
|
|
26
26
|
|
|
27
27
|
const DEFAULT_RECONNECT_DELAY_MS = 15 * 1000
|
|
@@ -54,11 +54,13 @@ class GrpcConnection extends EventEmitter {
|
|
|
54
54
|
this._metrics = metrics
|
|
55
55
|
this._setState(connectionStates.disconnected)
|
|
56
56
|
|
|
57
|
-
this._endpoint = this.getTraceObserverEndpoint(traceObserverConfig)
|
|
58
57
|
this._licensekey = null
|
|
59
58
|
this._runId = null
|
|
60
59
|
this._requestHeadersMap = null
|
|
61
60
|
|
|
61
|
+
this._endpoint = this.getTraceObserverEndpoint(traceObserverConfig)
|
|
62
|
+
|
|
63
|
+
this._client = null
|
|
62
64
|
this.stream = null
|
|
63
65
|
}
|
|
64
66
|
|
|
@@ -320,26 +322,48 @@ class GrpcConnection extends EventEmitter {
|
|
|
320
322
|
* a stream for further writing.
|
|
321
323
|
*/
|
|
322
324
|
_connectSpans() {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const credentials = this._generateCredentials(grpc)
|
|
330
|
-
const client = new serviceDefinition.IngestService(
|
|
331
|
-
this._endpoint,
|
|
332
|
-
credentials
|
|
333
|
-
)
|
|
325
|
+
if (!this._client) {
|
|
326
|
+
// Only create once to avoid potential memory leak.
|
|
327
|
+
// We create here (currently) for consistent error handling.
|
|
328
|
+
this._client = this._createClient(this._endpoint)
|
|
329
|
+
}
|
|
334
330
|
|
|
335
331
|
const metadata =
|
|
336
332
|
this._getMetadata(this._licenseKey, this._runId, this._requestHeadersMap, process.env)
|
|
337
333
|
|
|
338
|
-
const stream =
|
|
334
|
+
const stream = this._client.recordSpan(metadata)
|
|
339
335
|
this._setupSpanStreamObservers(stream)
|
|
340
336
|
|
|
341
337
|
return stream
|
|
342
338
|
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Creates gRPC service client to use for establishing gRPC streams.
|
|
342
|
+
*
|
|
343
|
+
* WARNING: creating a client more than once can result in a memory leak.
|
|
344
|
+
* ChannelImplementation and related objects will stay in memory even after
|
|
345
|
+
* the stream is closed and we do not have a handle to the client. Currently
|
|
346
|
+
* impacting grpc-js@1.2.11 and several earlier versions.
|
|
347
|
+
*/
|
|
348
|
+
_createClient(endpoint) {
|
|
349
|
+
logger.trace('Creating gRPC client for: ', endpoint)
|
|
350
|
+
|
|
351
|
+
const packageDefinition = protoLoader.loadSync(PROTO_DEFINITION_PATH, PROTO_OPTIONS)
|
|
352
|
+
|
|
353
|
+
const protoDescriptor = grpc.loadPackageDefinition(
|
|
354
|
+
packageDefinition
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
const traceApi = protoDescriptor.com.newrelic.trace.v1
|
|
358
|
+
|
|
359
|
+
const credentials = this._generateCredentials(grpc)
|
|
360
|
+
const client = new traceApi.IngestService(
|
|
361
|
+
endpoint,
|
|
362
|
+
credentials
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
return client
|
|
366
|
+
}
|
|
343
367
|
}
|
|
344
368
|
|
|
345
369
|
module.exports = GrpcConnection
|
|
@@ -40,7 +40,7 @@ function initialize(agent, shim) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
function tryAsyncHooks(agent, shim) {
|
|
43
|
-
|
|
43
|
+
let asyncHooks = null
|
|
44
44
|
try {
|
|
45
45
|
asyncHooks = require('async_hooks')
|
|
46
46
|
} catch (e) {
|
|
@@ -50,19 +50,45 @@ function tryAsyncHooks(agent, shim) {
|
|
|
50
50
|
|
|
51
51
|
// this map is reused to track the segment that was active when
|
|
52
52
|
// the before callback is called to be replaced in the after callback
|
|
53
|
-
|
|
53
|
+
const segmentMap = new Map()
|
|
54
54
|
module.exports.segmentMap = segmentMap
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
let hookHandlers = getStandardHooks(segmentMap, agent, shim)
|
|
57
|
+
|
|
58
|
+
if (agent.config.feature_flag.new_promise_tracking) {
|
|
59
|
+
logger.info('Enabling new promise tracking style via new_promise_tracking feature flag.')
|
|
60
|
+
hookHandlers = getPromiseResolveStyleHooks(segmentMap, agent, shim)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const hook = asyncHooks.createHook(hookHandlers)
|
|
64
|
+
hook.enable()
|
|
65
|
+
|
|
66
|
+
agent.on('unload', function disableHook() {
|
|
67
|
+
hook.disable()
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
return true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getStandardHooks(segmentMap, agent, shim) {
|
|
74
|
+
const hooks = {
|
|
57
75
|
init: function initHook(id, type, triggerId, promiseWrap) {
|
|
58
|
-
|
|
59
|
-
|
|
76
|
+
if (type !== 'PROMISE') {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const parentSegment = segmentMap.get(triggerId)
|
|
60
81
|
|
|
61
|
-
if (
|
|
82
|
+
if (parentSegment && !parentSegment.transaction.isActive()) {
|
|
83
|
+
// Stop propagating if the transaction was ended.
|
|
62
84
|
return
|
|
63
85
|
}
|
|
64
86
|
|
|
65
|
-
|
|
87
|
+
if (!parentSegment && !agent.getTransaction()) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const activeSegment = shim.getActiveSegment() || parentSegment
|
|
66
92
|
if (promiseWrap && promiseWrap.promise) {
|
|
67
93
|
promiseWrap.promise.__NR_id = id
|
|
68
94
|
}
|
|
@@ -70,7 +96,7 @@ function tryAsyncHooks(agent, shim) {
|
|
|
70
96
|
},
|
|
71
97
|
|
|
72
98
|
before: function beforeHook(id) {
|
|
73
|
-
|
|
99
|
+
const hookSegment = segmentMap.get(id)
|
|
74
100
|
|
|
75
101
|
if (!hookSegment) {
|
|
76
102
|
return
|
|
@@ -80,7 +106,7 @@ function tryAsyncHooks(agent, shim) {
|
|
|
80
106
|
shim.setActiveSegment(hookSegment)
|
|
81
107
|
},
|
|
82
108
|
after: function afterHook(id) {
|
|
83
|
-
|
|
109
|
+
const hookSegment = segmentMap.get(id)
|
|
84
110
|
|
|
85
111
|
// hookSegment is the segment that was active before the promise
|
|
86
112
|
// executed. If the promise is executing before a segment has been
|
|
@@ -96,11 +122,72 @@ function tryAsyncHooks(agent, shim) {
|
|
|
96
122
|
destroy: function destHook(id) {
|
|
97
123
|
segmentMap.delete(id)
|
|
98
124
|
}
|
|
99
|
-
}
|
|
125
|
+
}
|
|
100
126
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
})
|
|
127
|
+
return hooks
|
|
128
|
+
}
|
|
104
129
|
|
|
105
|
-
|
|
130
|
+
function getPromiseResolveStyleHooks(segmentMap, agent, shim) {
|
|
131
|
+
const hooks = {
|
|
132
|
+
init: function initHook(id, type, triggerId, asyncResource) {
|
|
133
|
+
if (type !== 'PROMISE') {
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let parentSegment = segmentMap.get(triggerId)
|
|
138
|
+
|
|
139
|
+
if (parentSegment && !parentSegment.transaction.isActive()) {
|
|
140
|
+
// Stop propagating if the transaction was ended.
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!parentSegment && !agent.getTransaction()) {
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const activeSegment = shim.getActiveSegment() || parentSegment
|
|
149
|
+
if (asyncResource && asyncResource.promise) {
|
|
150
|
+
asyncResource.promise.__NR_id = id
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
segmentMap.set(id, activeSegment)
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
before: function beforeHook(id) {
|
|
157
|
+
const hookSegment = segmentMap.get(id)
|
|
158
|
+
|
|
159
|
+
if (!hookSegment) {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
segmentMap.set(id, shim.getActiveSegment())
|
|
164
|
+
shim.setActiveSegment(hookSegment)
|
|
165
|
+
},
|
|
166
|
+
after: function afterHook(id) {
|
|
167
|
+
const hookSegment = segmentMap.get(id)
|
|
168
|
+
|
|
169
|
+
// hookSegment is the segment that was active before the promise
|
|
170
|
+
// executed. If the promise is executing before a segment has been
|
|
171
|
+
// restored, hookSegment will be null and should be restored. Thus
|
|
172
|
+
// undefined is the only invalid value here.
|
|
173
|
+
if (hookSegment === undefined) {
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
segmentMap.set(id, shim.getActiveSegment())
|
|
178
|
+
shim.setActiveSegment(hookSegment)
|
|
179
|
+
},
|
|
180
|
+
promiseResolve: function promiseResolveHandler(id) {
|
|
181
|
+
const hookSegment = segmentMap.get(id)
|
|
182
|
+
segmentMap.delete(id)
|
|
183
|
+
|
|
184
|
+
if (hookSegment === undefined) {
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
shim.setActiveSegment(hookSegment)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return hooks
|
|
106
193
|
}
|
|
@@ -267,6 +267,11 @@ function wrapResponseEnd(agent, proto) {
|
|
|
267
267
|
return end.apply(this, arguments)
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
if (!txInfo.transaction.isActive()) {
|
|
271
|
+
logger.trace('wrappedResEnd invoked for ended transaction implying multiple invocations.')
|
|
272
|
+
return end.apply(this, arguments)
|
|
273
|
+
}
|
|
274
|
+
|
|
270
275
|
// If an error happened, add it to the aggregator.
|
|
271
276
|
if (txInfo.error) {
|
|
272
277
|
if (!txInfo.errorHandled || urltils.isError(agent.config, this.statusCode)) {
|
|
@@ -61,7 +61,12 @@ function initialize(agent, timers, moduleName, shim) {
|
|
|
61
61
|
|
|
62
62
|
function wrapSetImmediate(shim, fn) {
|
|
63
63
|
return function wrappedSetImmediate() {
|
|
64
|
-
const
|
|
64
|
+
const segment = shim.getActiveSegment()
|
|
65
|
+
if (!segment) {
|
|
66
|
+
return fn.apply(this, arguments)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const args = shim.argsToArray.apply(shim, arguments, segment)
|
|
65
70
|
shim.bindSegment(args, shim.FIRST)
|
|
66
71
|
|
|
67
72
|
return fn.apply(this, args)
|
package/lib/metrics/names.js
CHANGED
|
@@ -22,7 +22,8 @@ const SUPPORTABILITY = {
|
|
|
22
22
|
NODEJS: 'Supportability/Nodejs',
|
|
23
23
|
REGISTRATION: 'Supportability/Registration',
|
|
24
24
|
EVENT_HARVEST: 'Supportability/EventHarvest',
|
|
25
|
-
INFINITE_TRACING: 'Supportability/InfiniteTracing'
|
|
25
|
+
INFINITE_TRACING: 'Supportability/InfiniteTracing',
|
|
26
|
+
FEATURES: 'Supportability/Features'
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
const ERRORS = {
|
|
@@ -249,6 +250,10 @@ const INFINITE_TRACING = {
|
|
|
249
250
|
DRAIN_DURATION: SUPPORTABILITY.INFINITE_TRACING + '/Drain/Duration',
|
|
250
251
|
}
|
|
251
252
|
|
|
253
|
+
const FEATURES = {
|
|
254
|
+
CERTIFICATES: SUPPORTABILITY.FEATURES + '/Certificates'
|
|
255
|
+
}
|
|
256
|
+
|
|
252
257
|
module.exports = {
|
|
253
258
|
ACTION_DELIMITER: '/',
|
|
254
259
|
ALL: ALL,
|
|
@@ -266,6 +271,7 @@ module.exports = {
|
|
|
266
271
|
EVENT_HARVEST: EVENT_HARVEST,
|
|
267
272
|
EXPRESS: EXPRESS,
|
|
268
273
|
EXTERNAL: EXTERNAL,
|
|
274
|
+
FEATURES,
|
|
269
275
|
FS: FS,
|
|
270
276
|
FUNCTION: FUNCTION,
|
|
271
277
|
GC: GC,
|
package/lib/shim/shim.js
CHANGED
|
@@ -1895,7 +1895,12 @@ function shimRequire(filePath) {
|
|
|
1895
1895
|
try {
|
|
1896
1896
|
return require(path.resolve(this._moduleRoot, filePath))
|
|
1897
1897
|
} catch (e) {
|
|
1898
|
-
this.logger.debug(
|
|
1898
|
+
this.logger.debug(
|
|
1899
|
+
'Failed to load \'%s\' from module root: \'%s\'. Stack: %s',
|
|
1900
|
+
filePath,
|
|
1901
|
+
this._moduleRoot,
|
|
1902
|
+
e.stack
|
|
1903
|
+
)
|
|
1899
1904
|
return null
|
|
1900
1905
|
}
|
|
1901
1906
|
}
|
|
@@ -72,6 +72,7 @@ function createStandardAggregator(config, collector, metrics) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
function validateInfiniteTracing(trace_observer) {
|
|
75
|
+
// TODO: Remove semver check when Node 10 support dropped.
|
|
75
76
|
if (!psemver.satisfies('>=10.10.0')) {
|
|
76
77
|
logger.warn(
|
|
77
78
|
'Infinite tracing disabled: this version of Node is not supported (must be >=10.10.0)'
|
package/lib/spans/span-event.js
CHANGED
|
@@ -9,7 +9,7 @@ const Config = require('../config')
|
|
|
9
9
|
const {truncate} = require('../util/byte-limit')
|
|
10
10
|
|
|
11
11
|
const {DESTINATIONS} = require('../config/attribute-filter')
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
const HTTP_LIBRARY = 'http'
|
|
14
14
|
const CLIENT_KIND = 'client'
|
|
15
15
|
const CATEGORIES = {
|
|
@@ -18,6 +18,9 @@ const CATEGORIES = {
|
|
|
18
18
|
GENERIC: 'generic'
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
const EXTERNAL_REGEX = /^(?:Truncated\/)?External\//
|
|
22
|
+
const DATASTORE_REGEX = /^(?:Truncated\/)?Datastore\//
|
|
23
|
+
|
|
21
24
|
const EMPTY_USER_ATTRS = Object.freeze(Object.create(null))
|
|
22
25
|
|
|
23
26
|
/**
|
|
@@ -200,7 +203,7 @@ class HttpSpanEvent extends SpanEvent {
|
|
|
200
203
|
}
|
|
201
204
|
|
|
202
205
|
static testSegment(segment) {
|
|
203
|
-
return segment.name
|
|
206
|
+
return EXTERNAL_REGEX.test(segment.name)
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
209
|
|
|
@@ -259,7 +262,7 @@ class DatastoreSpanEvent extends SpanEvent {
|
|
|
259
262
|
}
|
|
260
263
|
|
|
261
264
|
static testSegment(segment) {
|
|
262
|
-
return segment.name
|
|
265
|
+
return DATASTORE_REGEX.test(segment.name)
|
|
263
266
|
}
|
|
264
267
|
}
|
|
265
268
|
|
|
@@ -10,7 +10,7 @@ const {truncate} = require('../util/byte-limit')
|
|
|
10
10
|
const Config = require('../config')
|
|
11
11
|
|
|
12
12
|
const {DESTINATIONS} = require('../config/attribute-filter')
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
const HTTP_LIBRARY = 'http'
|
|
15
15
|
const CLIENT_KIND = 'client'
|
|
16
16
|
const CATEGORIES = {
|
|
@@ -19,6 +19,9 @@ const CATEGORIES = {
|
|
|
19
19
|
GENERIC: 'generic'
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
const EXTERNAL_REGEX = /^(?:Truncated\/)?External\//
|
|
23
|
+
const DATASTORE_REGEX = /^(?:Truncated\/)?Datastore\//
|
|
24
|
+
|
|
22
25
|
/**
|
|
23
26
|
* Specialized span event class for use with infinite streaming.
|
|
24
27
|
* Currently designed to be sent over grpc via the v1.proto definition.
|
|
@@ -200,7 +203,7 @@ class StreamingHttpSpanEvent extends StreamingSpanEvent {
|
|
|
200
203
|
}
|
|
201
204
|
|
|
202
205
|
static isHttpSegment(segment) {
|
|
203
|
-
return segment.name
|
|
206
|
+
return EXTERNAL_REGEX.test(segment.name)
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
209
|
|
|
@@ -269,7 +272,7 @@ class StreamingDatastoreSpanEvent extends StreamingSpanEvent {
|
|
|
269
272
|
}
|
|
270
273
|
|
|
271
274
|
static isDatastoreSegment(segment) {
|
|
272
|
-
return segment.name
|
|
275
|
+
return DATASTORE_REGEX.test(segment.name)
|
|
273
276
|
}
|
|
274
277
|
}
|
|
275
278
|
|
package/lib/transaction/index.js
CHANGED
|
@@ -225,9 +225,28 @@ Transaction.prototype.end = function end() {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
this.agent.emit('transactionFinished', this)
|
|
228
|
+
|
|
229
|
+
// Do after emit so all post-processing can complete
|
|
230
|
+
this._cleanUneededReferences()
|
|
231
|
+
|
|
228
232
|
return this
|
|
229
233
|
}
|
|
230
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Cleans up references that will not be used later for processing such as
|
|
237
|
+
* transaction traces.
|
|
238
|
+
*
|
|
239
|
+
* Errors won't be needed for later processing but can contain extra details we
|
|
240
|
+
* don't want to hold in memory. Particularly, axios errors can result in indirect
|
|
241
|
+
* references to promises which will prevent them from being destroyed and result
|
|
242
|
+
* in a memory leak. This is due to the TraceSegment not getting removed from the
|
|
243
|
+
* async-hooks segmentMap because 'destroy' never fires.
|
|
244
|
+
*/
|
|
245
|
+
Transaction.prototype._cleanUneededReferences = function _cleanUneededReferences() {
|
|
246
|
+
this.userErrors = null
|
|
247
|
+
this.exceptions = null
|
|
248
|
+
}
|
|
249
|
+
|
|
231
250
|
/**
|
|
232
251
|
* For web transactions, this represents the time from when the request was received
|
|
233
252
|
* to when response was sent. For background transactions, it is equal to duration
|
|
@@ -768,6 +787,11 @@ function _linkExceptionToSegment(exception) {
|
|
|
768
787
|
Transaction.prototype.addException = _addException
|
|
769
788
|
|
|
770
789
|
function _addException(exception) {
|
|
790
|
+
if (!this.isActive()) {
|
|
791
|
+
logger.trace('Transaction is not active. Not capturing error: ', exception)
|
|
792
|
+
return
|
|
793
|
+
}
|
|
794
|
+
|
|
771
795
|
this._linkExceptionToSegment(exception)
|
|
772
796
|
this.exceptions.push(exception)
|
|
773
797
|
}
|
|
@@ -782,6 +806,11 @@ function _addException(exception) {
|
|
|
782
806
|
Transaction.prototype.addUserError = _addUserError
|
|
783
807
|
|
|
784
808
|
function _addUserError(exception) {
|
|
809
|
+
if (!this.isActive()) {
|
|
810
|
+
logger.trace('Transaction is not active. Not capturing user error: ', exception)
|
|
811
|
+
return
|
|
812
|
+
}
|
|
813
|
+
|
|
785
814
|
this._linkExceptionToSegment(exception)
|
|
786
815
|
this.userErrors.push(exception)
|
|
787
816
|
}
|
|
@@ -879,6 +908,13 @@ Transaction.prototype.getIntrinsicAttributes = function getIntrinsicAttributes()
|
|
|
879
908
|
*/
|
|
880
909
|
Transaction.prototype.acceptDistributedTraceHeaders = acceptDistributedTraceHeaders
|
|
881
910
|
function acceptDistributedTraceHeaders(transportType, headers) {
|
|
911
|
+
if (headers == null || typeof headers !== 'object') {
|
|
912
|
+
logger.trace(
|
|
913
|
+
'Ignoring distributed trace headers for transaction %s. Headers not passed in as object.',
|
|
914
|
+
this.id)
|
|
915
|
+
return
|
|
916
|
+
}
|
|
917
|
+
|
|
882
918
|
const transport = TRANSPORT_TYPES_SET[transportType] ? transportType : TRANSPORT_TYPES.UNKNOWN
|
|
883
919
|
|
|
884
920
|
// assumes header keys already lowercase
|
package/newrelic.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"docs": "npm ci && jsdoc -c ./jsdoc-conf.json --private -r .",
|
|
126
126
|
"integration": "npm run prepare-test && npm run sub-install && time tap --no-esm test/integration/**/**/*.tap.js --timeout=180 --no-coverage",
|
|
127
127
|
"prepare-test": "npm ci && npm run ca-gen && npm run ssl && npm run docker-env",
|
|
128
|
-
"lint": "eslint ./*.js lib test",
|
|
128
|
+
"lint": "eslint ./*.js lib test bin",
|
|
129
129
|
"public-docs": "npm ci && jsdoc -c ./jsdoc-conf.json --tutorials examples/shim api.js lib/shim/ lib/transaction/handle.js && cp examples/shim/*.png out/",
|
|
130
130
|
"publish-docs": "./bin/publish-docs.sh",
|
|
131
131
|
"services": "./bin/docker-services.sh",
|
|
@@ -137,15 +137,14 @@
|
|
|
137
137
|
"update-cross-agent-tests": "./bin/update-cats.sh",
|
|
138
138
|
"versioned-tests": "./bin/run-versioned-tests.sh",
|
|
139
139
|
"update-changelog-version": "node ./bin/update-changelog-version",
|
|
140
|
-
"versioned": "npm run prepare-test && time ./bin/run-versioned-tests.sh"
|
|
141
|
-
"version": "npm run update-changelog-version && git add ./NEWS.md"
|
|
140
|
+
"versioned": "npm run prepare-test && time ./bin/run-versioned-tests.sh"
|
|
142
141
|
},
|
|
143
142
|
"bin": {
|
|
144
143
|
"newrelic-naming-rules": "./bin/test-naming-rules.js"
|
|
145
144
|
},
|
|
146
145
|
"dependencies": {
|
|
147
|
-
"@grpc/grpc-js": "^1.2.
|
|
148
|
-
"@grpc/proto-loader": "^0.5.
|
|
146
|
+
"@grpc/grpc-js": "^1.2.11",
|
|
147
|
+
"@grpc/proto-loader": "^0.5.6",
|
|
149
148
|
"@newrelic/aws-sdk": "^3.1.0",
|
|
150
149
|
"@newrelic/koa": "^5.0.0",
|
|
151
150
|
"@newrelic/superagent": "^4.0.0",
|
|
@@ -199,5 +198,18 @@
|
|
|
199
198
|
"repository": {
|
|
200
199
|
"type": "git",
|
|
201
200
|
"url": "https://github.com/newrelic/node-newrelic.git"
|
|
202
|
-
}
|
|
201
|
+
},
|
|
202
|
+
"files": [
|
|
203
|
+
"index.js",
|
|
204
|
+
"api.js",
|
|
205
|
+
"stub_api.js",
|
|
206
|
+
"newrelic.js",
|
|
207
|
+
"README.md",
|
|
208
|
+
"LICENSE",
|
|
209
|
+
"NEWS.md",
|
|
210
|
+
"THIRD_PARTY_NOTICES.md",
|
|
211
|
+
"lib/",
|
|
212
|
+
"bin/tracetractor",
|
|
213
|
+
"bin/test-naming-rules.js"
|
|
214
|
+
]
|
|
203
215
|
}
|
package/CONTRIBUTING.md
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# Guidelines for Contributing Code
|
|
2
|
-
|
|
3
|
-
New Relic welcomes code contributions by the Node community to this module, and
|
|
4
|
-
have taken effort to make this process easy for both contributors and our
|
|
5
|
-
development team.
|
|
6
|
-
|
|
7
|
-
## Process
|
|
8
|
-
|
|
9
|
-
### Feature Requests
|
|
10
|
-
|
|
11
|
-
Feature requests should be submitted in the [Issue tracker](../../issues), with
|
|
12
|
-
a description of the expected behavior & use case. Before submitting an Issue,
|
|
13
|
-
please search for similar ones in the [closed
|
|
14
|
-
issues](../../issues?q=is%3Aissue+is%3Aclosed+label%3Aenhancement).
|
|
15
|
-
|
|
16
|
-
### Pull Requests
|
|
17
|
-
|
|
18
|
-
We can only accept PRs for version v6.11.0 or greater due to open source
|
|
19
|
-
licensing restrictions.
|
|
20
|
-
|
|
21
|
-
### Code of Conduct
|
|
22
|
-
|
|
23
|
-
Before contributing please read the [code of conduct](https://github.com/newrelic/.github/blob/main/CODE_OF_CONDUCT.md)
|
|
24
|
-
|
|
25
|
-
Note that our [code of conduct](https://github.com/newrelic/.github/blob/main/CODE_OF_CONDUCT.md) applies to all platforms
|
|
26
|
-
and venues related to this project; please follow it in all your interactions
|
|
27
|
-
with the project and its participants.
|
|
28
|
-
|
|
29
|
-
### Contributor License Agreement
|
|
30
|
-
|
|
31
|
-
Keep in mind that when you submit your Pull Request, you'll need to sign the
|
|
32
|
-
CLA via the click-through using CLA-Assistant. If you'd like to execute our
|
|
33
|
-
corporate CLA, or if you have any questions, please drop us an email at
|
|
34
|
-
opensource@newrelic.com.
|
|
35
|
-
|
|
36
|
-
For more information about CLAs, please check out Alex Russell’s excellent
|
|
37
|
-
post, [“Why Do I Need to Sign
|
|
38
|
-
This?”](https://infrequently.org/2008/06/why-do-i-need-to-sign-this/).
|
|
39
|
-
|
|
40
|
-
### Slack
|
|
41
|
-
|
|
42
|
-
We host a public Slack with a dedicated channel for contributors and
|
|
43
|
-
maintainers of open source projects hosted by New Relic. If you are
|
|
44
|
-
contributing to this project, you're welcome to request access to the
|
|
45
|
-
\#oss-contributors channel in the newrelicusers.slack.com workspace. To request
|
|
46
|
-
access, see https://newrelicusers-signup.herokuapp.com/.
|
|
47
|
-
|
|
48
|
-
## PR Guidelines
|
|
49
|
-
|
|
50
|
-
### Version Support
|
|
51
|
-
|
|
52
|
-
When contributing, keep in mind that New Relic customers (that's you!) are running many different versions of Node, some of them pretty old. Changes that depend on the newest version of Node will probably be rejected, especially if they replace something backwards compatible.
|
|
53
|
-
|
|
54
|
-
Be aware that the instrumentation needs to work with a wide range of versions of the instrumented modules, and that code that looks nonsensical or overcomplicated may be that way for compatibility-related reasons. Read all the comments and check the related tests before deciding whether existing code is incorrect.
|
|
55
|
-
|
|
56
|
-
If you’re planning on contributing a new feature or an otherwise complex contribution, we kindly ask you to start a conversation with the maintainer team by opening up an Github issue first.
|
|
57
|
-
|
|
58
|
-
### General Guidelines
|
|
59
|
-
|
|
60
|
-
In general, we try to limit adding third-party production dependencies. If one is necessary, please be prepared to make a clear case for the need.
|
|
61
|
-
|
|
62
|
-
### Coding Style Guidelines/Conventions
|
|
63
|
-
|
|
64
|
-
We use eslint to enforce certain coding standards. Please see our [.eslintrc](./.eslintrc.js) file for specific rule configuration.
|
|
65
|
-
|
|
66
|
-
### Testing Guidelines
|
|
67
|
-
|
|
68
|
-
The agent includes a suite of unit and functional tests which should be used to
|
|
69
|
-
verify your changes don't break existing functionality.
|
|
70
|
-
|
|
71
|
-
Unit tests are stored in `test/`. They're written in
|
|
72
|
-
[node-tap](https://github.com/isaacs/node-tap), and have the extension `.test.js`.
|
|
73
|
-
|
|
74
|
-
Generic functional tests are stored in `test/integration/`. They're written in
|
|
75
|
-
[node-tap](https://github.com/isaacs/node-tap), and have the extension
|
|
76
|
-
`.tap.js`.
|
|
77
|
-
|
|
78
|
-
Functional tests against specific versions of instrumented modules are stored
|
|
79
|
-
in `test/versioned/`. They are also written in `node-tap`.
|
|
80
|
-
|
|
81
|
-
#### Setup
|
|
82
|
-
|
|
83
|
-
To run the tests you need an openssl command-line binary, and some services:
|
|
84
|
-
|
|
85
|
-
* Cassandra
|
|
86
|
-
* Memcached
|
|
87
|
-
* MongoDB
|
|
88
|
-
* MySQL
|
|
89
|
-
* Postgres
|
|
90
|
-
* Redis
|
|
91
|
-
|
|
92
|
-
If you have these all running locally on the standard ports, then you are good
|
|
93
|
-
to go. However, the suggested path is to use [Docker](http://www.docker.com).
|
|
94
|
-
If you use macOS or Windows, install [Docker Desktop]
|
|
95
|
-
(https://www.docker.com/products/docker-desktop). Then, run `npm run services`
|
|
96
|
-
to download and launch docker containers for each of the above services.
|
|
97
|
-
|
|
98
|
-
If you have these services available on non-standard ports or elsewhere on your
|
|
99
|
-
network, you can use the following environment variables to tell the tests
|
|
100
|
-
where they are:
|
|
101
|
-
|
|
102
|
-
* NR_NODE\_TEST_<service>\_HOST
|
|
103
|
-
* NR_NODE\_TEST_<service>\_PORT
|
|
104
|
-
|
|
105
|
-
The service token is the all-caps version of the service name listed above.
|
|
106
|
-
|
|
107
|
-
#### Running Tests
|
|
108
|
-
|
|
109
|
-
Running the test suite is simple. Just run:
|
|
110
|
-
|
|
111
|
-
npm test
|
|
112
|
-
|
|
113
|
-
This will install all the necessary modules (and do any required SSL
|
|
114
|
-
certificate creation) and run the unit tests in standalone mode, followed by
|
|
115
|
-
the functional tests if all of the unit tests pass.
|
|
116
|
-
|
|
117
|
-
If you don't feel like dealing with the hassle of setting up the servers, just
|
|
118
|
-
the unit tests can be run with:
|
|
119
|
-
|
|
120
|
-
npm run unit
|
|
121
|
-
|
|
122
|
-
#### Writing Tests
|
|
123
|
-
|
|
124
|
-
For most contributions it is strongly recommended to add additional tests which
|
|
125
|
-
exercise your changes. This helps us efficiently incorporate your changes into
|
|
126
|
-
our mainline codebase and provides a safeguard that your change won't be broken
|
|
127
|
-
by future development. Because of this, we require that all changes come with
|
|
128
|
-
tests. You are welcome to submit pull requests with untested changes, but they
|
|
129
|
-
won't be merged until you or the development team have an opportunity to write
|
|
130
|
-
tests for them.
|
|
131
|
-
|
|
132
|
-
There are some rare cases where code changes do not result in changed
|
|
133
|
-
functionality (e.g. a performance optimization) and new tests are not required.
|
|
134
|
-
In general, including tests with your pull request dramatically increases the
|
|
135
|
-
chances it will be accepted.
|