newrelic 6.13.2 → 7.0.2
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 +80 -7
- package/README.md +14 -5
- package/ROADMAP_Node.md +1 -1
- package/THIRD_PARTY_NOTICES.md +10 -12
- package/api.js +0 -32
- package/bin/run-versioned-tests.sh +3 -8
- package/index.js +5 -3
- package/lib/agent.js +4 -0
- package/lib/collector/api.js +2 -2
- package/lib/collector/http-agents.js +1 -1
- package/lib/collector/remote-method.js +18 -12
- package/lib/config/attribute-filter.js +1 -1
- package/lib/config/default.js +3 -11
- package/lib/config/env.js +0 -1
- package/lib/config/index.js +2 -23
- package/lib/db/parse-sql.js +1 -1
- package/lib/db/query-parsers/sql.js +1 -1
- package/lib/errors/error-collector.js +6 -1
- package/lib/errors/index.js +14 -1
- package/lib/grpc/connection.js +28 -4
- package/lib/instrumentation/core/http.js +34 -82
- package/lib/instrumentation/fastify/spec-builders.js +1 -1
- package/lib/metrics/names.js +4 -1
- package/lib/parse-proc-cpuinfo.js +1 -1
- package/lib/proxy/grpc.js +1 -1
- package/lib/serverless/aws-lambda.js +9 -23
- package/lib/shim/promise-shim.js +1 -1
- package/lib/shim/shim.js +3 -3
- package/lib/shim/transaction-shim.js +1 -1
- package/lib/shim/webframework-shim.js +1 -1
- package/lib/shimmer.js +1 -1
- package/lib/spans/create-span-event-aggregator.js +1 -1
- package/lib/spans/span-context.js +18 -0
- package/lib/spans/span-event.js +13 -2
- package/lib/spans/span-streamer.js +24 -13
- package/lib/spans/streaming-span-event-aggregator.js +4 -0
- package/lib/spans/streaming-span-event.js +13 -1
- package/lib/timer.js +1 -1
- package/lib/transaction/dt-payload.js +2 -2
- package/lib/transaction/handle.js +0 -54
- package/lib/transaction/index.js +25 -39
- package/lib/transaction/tracecontext.js +19 -4
- package/lib/util/byte-limit.js +1 -1
- package/lib/utilization/common.js +1 -1
- package/newrelic.js +1 -1
- package/package.json +11 -11
- package/stub_api.js +1 -1
- package/third_party_manifest.json +36 -36
package/lib/grpc/connection.js
CHANGED
|
@@ -38,7 +38,7 @@ class GrpcConnection extends EventEmitter {
|
|
|
38
38
|
/**
|
|
39
39
|
* GrpcConnection constructor
|
|
40
40
|
*
|
|
41
|
-
* Standard property setting/
|
|
41
|
+
* Standard property setting/initialization, and sets an initial
|
|
42
42
|
* connection state of disconnected
|
|
43
43
|
*
|
|
44
44
|
* @param {Object} traceObserverConfig config item config.infinite_tracing.trace_observer
|
|
@@ -121,7 +121,7 @@ class GrpcConnection extends EventEmitter {
|
|
|
121
121
|
// immediately.
|
|
122
122
|
this._setState(connectionStates.connected, this.stream)
|
|
123
123
|
} catch (err) {
|
|
124
|
-
logger.
|
|
124
|
+
logger.warn(
|
|
125
125
|
err,
|
|
126
126
|
'Unexpected error establishing gRPC stream, will not attempt reconnect.'
|
|
127
127
|
)
|
|
@@ -198,9 +198,26 @@ class GrpcConnection extends EventEmitter {
|
|
|
198
198
|
if (this.stream) {
|
|
199
199
|
this.stream.removeAllListeners()
|
|
200
200
|
|
|
201
|
+
const oldStream = this.stream
|
|
202
|
+
this.stream.on('status', function endStreamStatusHandler(grpcStatus) {
|
|
203
|
+
logger.trace('End stream status received [%s]: %s', grpcStatus.code, grpcStatus.details)
|
|
204
|
+
|
|
205
|
+
// Cleanup the final end stream listeners.
|
|
206
|
+
oldStream.removeAllListeners()
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
// Listen to any final errors to prevent throwing.
|
|
210
|
+
// This is unlikely but if the server closes post
|
|
211
|
+
// removing listeners and prior to response it could
|
|
212
|
+
// happen. We noticed this via tests on Node 14.
|
|
213
|
+
this.stream.on('error', function endStreamErrorHandler(err) {
|
|
214
|
+
logger.trace('End stream error received. Code: [%s]: %s', err.code, err.details)
|
|
215
|
+
})
|
|
216
|
+
|
|
201
217
|
// Indicates to server we are done.
|
|
202
218
|
// Server officially closes the stream.
|
|
203
219
|
this.stream.end()
|
|
220
|
+
|
|
204
221
|
this.stream = null
|
|
205
222
|
}
|
|
206
223
|
|
|
@@ -238,6 +255,9 @@ class GrpcConnection extends EventEmitter {
|
|
|
238
255
|
// per the spec, An UNIMPLEMENTED status code from gRPC indicates
|
|
239
256
|
// that the versioned Trace Observer is no longer available. Agents
|
|
240
257
|
// MUST NOT attempt to reconnect in this case
|
|
258
|
+
logger.info(
|
|
259
|
+
'[UNIMPLEMENTED]: Trace Obserserver is no longer available. Shutting down connection.'
|
|
260
|
+
)
|
|
241
261
|
this._disconnect()
|
|
242
262
|
} else if (grpc.status[grpc.status.OK] === grpcStatusName) {
|
|
243
263
|
this._reconnect()
|
|
@@ -256,7 +276,11 @@ class GrpcConnection extends EventEmitter {
|
|
|
256
276
|
this._metrics.getOrCreateMetric(NAMES.INFINITE_TRACING.SPAN_RESPONSE_ERROR)
|
|
257
277
|
.incrementCallCount()
|
|
258
278
|
|
|
259
|
-
|
|
279
|
+
// For errors, the status will either result in a disconnect or a reconnect
|
|
280
|
+
// delay that should prevent too frequent spamming. Unless the app is idle
|
|
281
|
+
// and regularly getting Status 13 reconnects from the server, in which case
|
|
282
|
+
// this will be almost the only logging.
|
|
283
|
+
logger.warn('Span stream error. Code: [%s]: %s', err.code, err.details)
|
|
260
284
|
})
|
|
261
285
|
}
|
|
262
286
|
|
|
@@ -266,7 +290,7 @@ class GrpcConnection extends EventEmitter {
|
|
|
266
290
|
_generateCredentials(grpcApi) {
|
|
267
291
|
let certBuffer = null
|
|
268
292
|
|
|
269
|
-
// Current settable value for testing. If allowed to be
|
|
293
|
+
// Current settable value for testing. If allowed to be overridden via
|
|
270
294
|
// configuration, this should be removed in place of setting
|
|
271
295
|
// this._rootCerts from config via normal configuration precedence.
|
|
272
296
|
const envTestCerts = process.env.NEWRELIC_GRPCCONNECTION_CA
|
|
@@ -15,7 +15,6 @@ const util = require('util')
|
|
|
15
15
|
const url = require('url')
|
|
16
16
|
const urltils = require('../../util/urltils')
|
|
17
17
|
const properties = require('../../util/properties')
|
|
18
|
-
const psemver = require('../../util/process-version')
|
|
19
18
|
const headerAttributes = require('../../header-attributes')
|
|
20
19
|
const headerProcessing = require('../../header-processing')
|
|
21
20
|
|
|
@@ -27,8 +26,6 @@ const DESTS = require('../../config/attribute-filter').DESTINATIONS
|
|
|
27
26
|
* CONSTANTS
|
|
28
27
|
*
|
|
29
28
|
*/
|
|
30
|
-
const SHOULD_WRAP_HTTPS = psemver.satisfies('>=9.0.0 || 8.9.0')
|
|
31
|
-
const SHOULD_FORMAT_ARGS = psemver.satisfies('>=10.0.0')
|
|
32
29
|
const NR_CONNECTION_PROP = '__NR__connection'
|
|
33
30
|
const NEWRELIC_ID_HEADER = 'x-newrelic-id'
|
|
34
31
|
const NEWRELIC_APP_DATA_HEADER = 'x-newrelic-app-data'
|
|
@@ -172,16 +169,7 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
172
169
|
|
|
173
170
|
if (response) {
|
|
174
171
|
if (response.statusCode != null) {
|
|
175
|
-
/*
|
|
176
|
-
TODO: remove with next major release
|
|
177
|
-
httpResponseCode attribute is deprecated
|
|
178
|
-
*/
|
|
179
172
|
var responseCode = String(response.statusCode)
|
|
180
|
-
transaction.trace.attributes.addAttribute(
|
|
181
|
-
DESTS.TRANS_COMMON,
|
|
182
|
-
'httpResponseCode',
|
|
183
|
-
responseCode
|
|
184
|
-
)
|
|
185
173
|
|
|
186
174
|
if (/^\d+$/.test(responseCode)) {
|
|
187
175
|
transaction.trace.attributes.addAttribute(
|
|
@@ -189,18 +177,8 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
189
177
|
'http.statusCode',
|
|
190
178
|
responseCode
|
|
191
179
|
)
|
|
192
|
-
|
|
193
|
-
segment.addSpanAttribute('http.statusCode', responseCode)
|
|
194
180
|
|
|
195
|
-
|
|
196
|
-
TODO: remove with next major release
|
|
197
|
-
response.status attribute is deprecated
|
|
198
|
-
*/
|
|
199
|
-
transaction.trace.attributes.addAttribute(
|
|
200
|
-
DESTS.TRANS_COMMON,
|
|
201
|
-
'response.status',
|
|
202
|
-
responseCode
|
|
203
|
-
)
|
|
181
|
+
segment.addSpanAttribute('http.statusCode', responseCode)
|
|
204
182
|
}
|
|
205
183
|
}
|
|
206
184
|
|
|
@@ -212,16 +190,6 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
212
190
|
)
|
|
213
191
|
|
|
214
192
|
segment.addSpanAttribute('http.statusText', response.statusMessage)
|
|
215
|
-
|
|
216
|
-
/*
|
|
217
|
-
TODO: remove with next major release
|
|
218
|
-
httpResponseMessage attribute is deprecated
|
|
219
|
-
*/
|
|
220
|
-
transaction.trace.attributes.addAttribute(
|
|
221
|
-
DESTS.TRANS_COMMON,
|
|
222
|
-
'httpResponseMessage',
|
|
223
|
-
response.statusMessage
|
|
224
|
-
)
|
|
225
193
|
}
|
|
226
194
|
|
|
227
195
|
var headers = response.getHeaders()
|
|
@@ -299,7 +267,7 @@ function wrapResponseEnd(agent, proto) {
|
|
|
299
267
|
return end.apply(this, arguments)
|
|
300
268
|
}
|
|
301
269
|
|
|
302
|
-
// If an error
|
|
270
|
+
// If an error happened, add it to the aggregator.
|
|
303
271
|
if (txInfo.error) {
|
|
304
272
|
if (!txInfo.errorHandled || urltils.isError(agent.config, this.statusCode)) {
|
|
305
273
|
agent.errors.add(txInfo.transaction, txInfo.error)
|
|
@@ -323,7 +291,7 @@ function wrapResponseEnd(agent, proto) {
|
|
|
323
291
|
})
|
|
324
292
|
}
|
|
325
293
|
|
|
326
|
-
// CAT this
|
|
294
|
+
// CAT this won't be used unless CAT is enabled, see below where we actually do
|
|
327
295
|
// the shimmer stuff if you'd like to verify.
|
|
328
296
|
function wrapWriteHead(agent, writeHead) {
|
|
329
297
|
return function wrappedWriteHead() {
|
|
@@ -442,37 +410,30 @@ function urlToOptions(_url) {
|
|
|
442
410
|
}
|
|
443
411
|
|
|
444
412
|
function wrapRequest(agent, request) {
|
|
445
|
-
// URL as a global was not added until Node v10
|
|
446
|
-
const URLClass = global.URL ? global.URL : url.URL
|
|
447
413
|
return function wrappedRequest(input, options, cb) {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
} else if (input.constructor && input.constructor.name === 'URL') {
|
|
456
|
-
input = urlToOptions(input)
|
|
457
|
-
} else {
|
|
458
|
-
cb = options
|
|
459
|
-
options = input
|
|
460
|
-
input = null
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (typeof options === 'function') {
|
|
464
|
-
cb = options
|
|
465
|
-
options = input || {}
|
|
466
|
-
} else {
|
|
467
|
-
options = Object.assign(input || {}, options)
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
reqArgs = [options, cb]
|
|
414
|
+
// If the first argument is a URL, merge it into the options object.
|
|
415
|
+
// This code is copied from Node internals.
|
|
416
|
+
if (typeof input === 'string') {
|
|
417
|
+
const urlStr = input
|
|
418
|
+
input = urlToOptions(new URL(urlStr))
|
|
419
|
+
} else if (input.constructor && input.constructor.name === 'URL') {
|
|
420
|
+
input = urlToOptions(input)
|
|
471
421
|
} else {
|
|
472
|
-
|
|
422
|
+
cb = options
|
|
473
423
|
options = input
|
|
424
|
+
input = null
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (typeof options === 'function') {
|
|
428
|
+
cb = options
|
|
429
|
+
options = input || {}
|
|
430
|
+
} else {
|
|
431
|
+
options = Object.assign(input || {}, options)
|
|
474
432
|
}
|
|
475
433
|
|
|
434
|
+
let reqArgs = [options, cb]
|
|
435
|
+
|
|
436
|
+
|
|
476
437
|
// Don't pollute metrics and calls with NR connections
|
|
477
438
|
const internalOnly = options && options[NR_CONNECTION_PROP]
|
|
478
439
|
if (internalOnly) {
|
|
@@ -552,28 +513,19 @@ module.exports = function initialize(agent, http, moduleName) {
|
|
|
552
513
|
|
|
553
514
|
var agentProto = http && http.Agent && http.Agent.prototype
|
|
554
515
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
// TODO: Remove `SHOULD_WRAP_HTTPS` after deprecating Node <9.
|
|
562
|
-
if (SHOULD_WRAP_HTTPS || !IS_HTTPS) {
|
|
563
|
-
shimmer.wrapMethod(
|
|
564
|
-
http,
|
|
565
|
-
'http',
|
|
566
|
-
'request',
|
|
567
|
-
wrapRequest.bind(null, agent)
|
|
568
|
-
)
|
|
516
|
+
shimmer.wrapMethod(
|
|
517
|
+
http,
|
|
518
|
+
'http',
|
|
519
|
+
'request',
|
|
520
|
+
wrapRequest.bind(null, agent)
|
|
521
|
+
)
|
|
569
522
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
}
|
|
523
|
+
shimmer.wrapMethod(
|
|
524
|
+
http,
|
|
525
|
+
'http',
|
|
526
|
+
'get',
|
|
527
|
+
wrapRequest.bind(null, agent)
|
|
528
|
+
)
|
|
577
529
|
|
|
578
530
|
shimmer.wrapMethod(
|
|
579
531
|
agentProto,
|
|
@@ -59,7 +59,7 @@ function buildMiddlewareSpecForRouteHandler(shim, path) {
|
|
|
59
59
|
* then this method is required/useful again.
|
|
60
60
|
*
|
|
61
61
|
* The isFinal param determines whether or not a path is appended for
|
|
62
|
-
* this
|
|
62
|
+
* this particular piece of middleware. (i.e. if this is the final handler
|
|
63
63
|
* that is actually handling the request, the path is actually left on)
|
|
64
64
|
*/
|
|
65
65
|
next: function wrapNext(shim, fn, fnName, args, bindSegment) {
|
package/lib/metrics/names.js
CHANGED
|
@@ -240,10 +240,13 @@ const SPAN_EVENTS = {
|
|
|
240
240
|
const INFINITE_TRACING = {
|
|
241
241
|
SEEN: SUPPORTABILITY.INFINITE_TRACING + '/Span/Seen',
|
|
242
242
|
SENT: SUPPORTABILITY.INFINITE_TRACING + '/Span/Sent',
|
|
243
|
+
DROPPED: SUPPORTABILITY.INFINITE_TRACING + '/Span/Dropped',
|
|
243
244
|
SPAN_RESPONSE_ERROR: SUPPORTABILITY.INFINITE_TRACING + '/Span/Response/Error',
|
|
244
245
|
SPAN_RESPONSE_GRPC_UNIMPLEMENTED: SUPPORTABILITY.INFINITE_TRACING + '/Span/gRPC/UNIMPLEMENTED',
|
|
245
246
|
SPAN_RESPONSE_GRPC_STATUS: SUPPORTABILITY.INFINITE_TRACING + '/Span/gRPC/%s',
|
|
246
|
-
|
|
247
|
+
QUEUE_CAPACITY: SUPPORTABILITY.INFINITE_TRACING + '/Span/QueueCapacity',
|
|
248
|
+
QUEUE_SIZE: SUPPORTABILITY.INFINITE_TRACING + '/Span/QueueSize',
|
|
249
|
+
DRAIN_DURATION: SUPPORTABILITY.INFINITE_TRACING + '/Drain/Duration',
|
|
247
250
|
}
|
|
248
251
|
|
|
249
252
|
module.exports = {
|
package/lib/proxy/grpc.js
CHANGED
|
@@ -8,7 +8,7 @@ class ProxyGrpc {
|
|
|
8
8
|
constructor(grpcLibrary = '@grpc/grpc-js') {
|
|
9
9
|
this.library = require(grpcLibrary)
|
|
10
10
|
|
|
11
|
-
// add methods or
|
|
11
|
+
// add methods or objects from base grpc class that we need as needed
|
|
12
12
|
this.credentials = this.library.credentials
|
|
13
13
|
this.Metadata = this.library.Metadata
|
|
14
14
|
this.loadPackageDefinition = this.library.loadPackageDefinition
|
|
@@ -129,7 +129,6 @@ class AwsLambda {
|
|
|
129
129
|
const segmentRecorder = isApiGatewayLambdaProxy ? recordWeb : recordBackground
|
|
130
130
|
const segment = shim.createSegment(functionName, segmentRecorder)
|
|
131
131
|
transaction.baseSegment = segment
|
|
132
|
-
|
|
133
132
|
// resultProcessor is used to execute additional logic based on the
|
|
134
133
|
// payload supplied to the callback.
|
|
135
134
|
let resultProcessor
|
|
@@ -180,7 +179,6 @@ class AwsLambda {
|
|
|
180
179
|
shim.agent.setLambdaArn(context.invokedFunctionArn)
|
|
181
180
|
|
|
182
181
|
shim.agent.setLambdaFunctionVersion(context.functionVersion)
|
|
183
|
-
|
|
184
182
|
segment.addSpanAttributes(awsAttributes)
|
|
185
183
|
|
|
186
184
|
segment.start()
|
|
@@ -194,7 +192,7 @@ class AwsLambda {
|
|
|
194
192
|
throw err
|
|
195
193
|
}
|
|
196
194
|
if (shim.isPromise(res)) {
|
|
197
|
-
res = lambdaInterceptPromise(res, txnEnder)
|
|
195
|
+
res = lambdaInterceptPromise(res, resultProcessor, txnEnder)
|
|
198
196
|
}
|
|
199
197
|
return res
|
|
200
198
|
}
|
|
@@ -202,8 +200,11 @@ class AwsLambda {
|
|
|
202
200
|
// In order to capture error events
|
|
203
201
|
// we need to store the error in uncaughtException
|
|
204
202
|
// otherwise the transaction will end before they are captured
|
|
205
|
-
function lambdaInterceptPromise(prom, cb) {
|
|
203
|
+
function lambdaInterceptPromise(prom, resultProcessor, cb) {
|
|
206
204
|
return prom.then(function onThen(arg) {
|
|
205
|
+
if (resultProcessor) {
|
|
206
|
+
resultProcessor(arg)
|
|
207
|
+
}
|
|
207
208
|
cb()
|
|
208
209
|
return arg
|
|
209
210
|
}, function onCatch(err) {
|
|
@@ -389,33 +390,18 @@ function setWebResponse(transaction, response) {
|
|
|
389
390
|
transaction.statusCode = response.statusCode
|
|
390
391
|
|
|
391
392
|
const responseCode = String(response.statusCode)
|
|
392
|
-
/*
|
|
393
|
-
TODO: remove with next major release
|
|
394
|
-
httpResponseCode attribute is deprecated
|
|
395
|
-
*/
|
|
396
|
-
transaction.trace.attributes.addAttribute(
|
|
397
|
-
ATTR_DEST.TRANS_COMMON,
|
|
398
|
-
'httpResponseCode',
|
|
399
|
-
responseCode
|
|
400
|
-
)
|
|
401
393
|
|
|
402
394
|
if (/^\d+$/.test(responseCode)) {
|
|
403
|
-
/*
|
|
404
|
-
TODO: remove with next major release
|
|
405
|
-
response.status attribute is deprecated
|
|
406
|
-
*/
|
|
407
|
-
transaction.trace.attributes.addAttribute(
|
|
408
|
-
ATTR_DEST.TRANS_COMMON,
|
|
409
|
-
'response.status',
|
|
410
|
-
responseCode)
|
|
411
|
-
|
|
412
395
|
transaction.trace.attributes.addAttribute(
|
|
413
396
|
ATTR_DEST.TRANS_COMMON,
|
|
414
397
|
'http.statusCode',
|
|
415
398
|
responseCode
|
|
416
399
|
)
|
|
417
400
|
|
|
418
|
-
|
|
401
|
+
// We are adding http.statusCode to base segment as
|
|
402
|
+
// we found in testing async invoked lambdas, the
|
|
403
|
+
// active segement is not available at this point.
|
|
404
|
+
const segment = transaction.baseSegment
|
|
419
405
|
|
|
420
406
|
segment.addSpanAttribute('http.statusCode', responseCode)
|
|
421
407
|
}
|
package/lib/shim/promise-shim.js
CHANGED
|
@@ -46,7 +46,7 @@ class PromiseShim extends Shim {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Sets the class used to
|
|
49
|
+
* Sets the class used to identify promises from the wrapped promise library.
|
|
50
50
|
*
|
|
51
51
|
* @param {function} clss - The promise library's class.
|
|
52
52
|
*/
|
package/lib/shim/shim.js
CHANGED
|
@@ -308,7 +308,7 @@ Shim.prototype.__NR_unwrap = unwrapAll
|
|
|
308
308
|
*
|
|
309
309
|
* @description
|
|
310
310
|
* The syntax for declarative instrumentation. It can be used interlaced with
|
|
311
|
-
* custom, hand-written instrumentation for one-off or hard to
|
|
311
|
+
* custom, hand-written instrumentation for one-off or hard to simplify
|
|
312
312
|
* instrumentation logic.
|
|
313
313
|
*
|
|
314
314
|
* @property {Spec|WrapFunction} $return
|
|
@@ -1949,10 +1949,10 @@ function bindPromise(promise, segment) {
|
|
|
1949
1949
|
* Copies the given parameters onto the segment, respecting the current agent
|
|
1950
1950
|
* configuration.
|
|
1951
1951
|
*
|
|
1952
|
-
* @memberof Shim.
|
|
1952
|
+
* @memberof Shim.prototype
|
|
1953
1953
|
*
|
|
1954
1954
|
* @param {TraceSegment} segment - The segment to copy the parameters onto.
|
|
1955
|
-
* @param {object} parameters - The
|
|
1955
|
+
* @param {object} parameters - The parameters to copy.
|
|
1956
1956
|
*/
|
|
1957
1957
|
function copySegmentParameters(segment, parameters) {
|
|
1958
1958
|
for (var key in parameters) {
|
|
@@ -184,7 +184,7 @@ function bindCreateTransaction(nodule, property, spec) {
|
|
|
184
184
|
*
|
|
185
185
|
* - `pushTransactionName(pathSegment)`
|
|
186
186
|
*
|
|
187
|
-
* Transactions are named for the middlware that sends the
|
|
187
|
+
* Transactions are named for the middlware that sends the response. Some web
|
|
188
188
|
* frameworks are capable of mounting middlware in complex routing stacks. In
|
|
189
189
|
* order to maintain the correct name, transactions keep a stack of mount points
|
|
190
190
|
* for each middlware/router/app/whatever. The instrumentation should push on
|
|
@@ -331,7 +331,7 @@ function setFramework(framework) {
|
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
/**
|
|
334
|
-
* Sets the URI path to be used for naming the transaction
|
|
334
|
+
* Sets the URI path to be used for naming the transaction currently in scope.
|
|
335
335
|
*
|
|
336
336
|
* @memberof WebFrameworkShim.prototype
|
|
337
337
|
*
|
package/lib/shimmer.js
CHANGED
|
@@ -381,7 +381,7 @@ var shimmer = module.exports = {
|
|
|
381
381
|
* Forces file name resolve for modules not in our cache when
|
|
382
382
|
* their parent has already been loaded/cached by Node.
|
|
383
383
|
* Provides a fall-back for unexpected cases that may occur.
|
|
384
|
-
* Also provides
|
|
384
|
+
* Also provides flexibility for testing now that node 11+ caches these.
|
|
385
385
|
* @param {*} request
|
|
386
386
|
* @param {*} parent
|
|
387
387
|
* @param {*} isMain
|
|
@@ -16,7 +16,7 @@ function createSpanEventAggregator(config, collector, metrics) {
|
|
|
16
16
|
// TODO: ideally this validation and configuration clearing would happen
|
|
17
17
|
// in the config. Since we don't currently have a way to generate
|
|
18
18
|
// support metrics in the config, keeping this related logic together here.
|
|
19
|
-
// If logic happened prior, could merely check for
|
|
19
|
+
// If logic happened prior, could merely check for existence of trace_observer.host.
|
|
20
20
|
shouldCreateStreaming = validateInfiniteTracing(config.infinite_tracing.trace_observer)
|
|
21
21
|
|
|
22
22
|
if (!shouldCreateStreaming) {
|
|
@@ -21,6 +21,9 @@ class SpanContext {
|
|
|
21
21
|
customAttributes || new PrioritizedAttributes(ATTRIBUTE_SCOPE, MAXIMUM_CUSTOM_ATTRIBUTES)
|
|
22
22
|
|
|
23
23
|
this.ATTRIBUTE_PRIORITY = ATTRIBUTE_PRIORITY
|
|
24
|
+
|
|
25
|
+
this.hasError = false
|
|
26
|
+
this.errorDetails = null
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
addIntrinsicAttribute(key, value) {
|
|
@@ -36,6 +39,21 @@ class SpanContext {
|
|
|
36
39
|
priority
|
|
37
40
|
)
|
|
38
41
|
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Set error details to be potentially be used to create span
|
|
45
|
+
* attributes. Attributes will be created unless the transaction
|
|
46
|
+
* ends with an ignored error status code.
|
|
47
|
+
*
|
|
48
|
+
* Last error wins.
|
|
49
|
+
*/
|
|
50
|
+
setError(details) {
|
|
51
|
+
this.hasError = true
|
|
52
|
+
|
|
53
|
+
// Error details will be used to create attributes unless the transaction ends
|
|
54
|
+
// with an ignored status code.
|
|
55
|
+
this.errorDetails = details
|
|
56
|
+
}
|
|
39
57
|
}
|
|
40
58
|
|
|
41
59
|
module.exports = SpanContext
|
package/lib/spans/span-event.js
CHANGED
|
@@ -84,9 +84,21 @@ class SpanEvent {
|
|
|
84
84
|
* @return {SpanEvent} The constructed event.
|
|
85
85
|
*/
|
|
86
86
|
static fromSegment(segment, parentId = null, isRoot = false) {
|
|
87
|
+
const spanContext = segment.getSpanContext()
|
|
88
|
+
|
|
89
|
+
// Since segments already hold span agent attributes and we want to leverage
|
|
90
|
+
// filtering, we add to the segment attributes prior to processing.
|
|
91
|
+
if (spanContext.hasError && !segment.transaction.hasIgnoredErrorStatusCode()) {
|
|
92
|
+
const details = spanContext.errorDetails
|
|
93
|
+
segment.addSpanAttribute('error.message', details.message)
|
|
94
|
+
segment.addSpanAttribute('error.class', details.type)
|
|
95
|
+
if (details.expected) {
|
|
96
|
+
segment.addSpanAttribute('error.expected', details.expected)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
87
100
|
const attributes = segment.attributes.get(DESTINATIONS.SPAN_EVENT)
|
|
88
101
|
|
|
89
|
-
const spanContext = segment.getSpanContext()
|
|
90
102
|
const customAttributes = spanContext.customAttributes.get(DESTINATIONS.SPAN_EVENT)
|
|
91
103
|
|
|
92
104
|
let span = null
|
|
@@ -98,7 +110,6 @@ class SpanEvent {
|
|
|
98
110
|
span = new SpanEvent(attributes, customAttributes)
|
|
99
111
|
}
|
|
100
112
|
|
|
101
|
-
|
|
102
113
|
for (const [key, value] of Object.entries(spanContext.intrinsicAttributes)) {
|
|
103
114
|
span.intrinsics[key] = value
|
|
104
115
|
}
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
const logger = require('../logger').child({component: 'span-streamer'})
|
|
9
9
|
const NAMES = require('../metrics/names').INFINITE_TRACING
|
|
10
10
|
|
|
11
|
+
const SPAN_DROP_MSG_INTERVAL_MS = 30000
|
|
11
12
|
const SPAN_DROP_MSG =
|
|
12
|
-
'Queue full, dropping spans.'
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
'Queue full, dropping spans. ' +
|
|
14
|
+
`Will not warn again for ${SPAN_DROP_MSG_INTERVAL_MS / 1000} seconds.`
|
|
15
15
|
|
|
16
16
|
class SpanStreamer {
|
|
17
17
|
constructor(license_key, connection, metrics, queue_size) {
|
|
@@ -47,21 +47,20 @@ class SpanStreamer {
|
|
|
47
47
|
|
|
48
48
|
// If not writeable (because of backpressure) queue the span
|
|
49
49
|
if (!this._writable) {
|
|
50
|
-
if (this.spans.length
|
|
50
|
+
if (this.spans.length < this.queue_size) {
|
|
51
51
|
this.spans.push(span)
|
|
52
52
|
return
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
// While this can be directionally calculated between seen/sent the
|
|
56
|
+
// queue makes that a bit more disconnected. This will be a bit more specific.
|
|
57
|
+
this._metrics.getOrCreateMetric(NAMES.DROPPED).incrementCallCount()
|
|
58
|
+
|
|
55
59
|
// If the queue is full drop the span
|
|
56
60
|
logger.infoOncePer(
|
|
57
|
-
// key for the OncePer
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
SPAN_DROP_INTERVAL * 1000,
|
|
61
|
-
// message
|
|
62
|
-
SPAN_DROP_MSG + ' Will not warn again for %s seconds.',
|
|
63
|
-
// variables to put in log message
|
|
64
|
-
SPAN_DROP_INTERVAL
|
|
61
|
+
'SPAN_DROP_MSG', // key for the OncePer
|
|
62
|
+
SPAN_DROP_MSG_INTERVAL_MS,
|
|
63
|
+
SPAN_DROP_MSG
|
|
65
64
|
)
|
|
66
65
|
|
|
67
66
|
return
|
|
@@ -121,14 +120,21 @@ class SpanStreamer {
|
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
sendQueue() {
|
|
123
|
+
logger.trace('Sending spans from queue.')
|
|
124
|
+
|
|
124
125
|
// Continue sending the spans that were in the queue. _writable is checked
|
|
125
126
|
// so that if a send fails while clearing the queue, this drain handler can
|
|
126
127
|
// finish, and the drain handler setup on the failed send will then attempt
|
|
127
128
|
// to clear the queue
|
|
128
129
|
while (this.spans.length > 0 && this._writable) {
|
|
129
130
|
const nextObject = this.spans.shift()
|
|
130
|
-
this.send(nextObject)
|
|
131
|
+
this.send(nextObject.toStreamingFormat())
|
|
131
132
|
}
|
|
133
|
+
|
|
134
|
+
logger.trace(
|
|
135
|
+
'Finished sending spans from queue. Items left in queue: %s',
|
|
136
|
+
this.spans.length
|
|
137
|
+
)
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
connect(agent_run_id, requestHeadersMap) {
|
|
@@ -144,6 +150,11 @@ class SpanStreamer {
|
|
|
144
150
|
disconnect() {
|
|
145
151
|
this.connection.disconnect()
|
|
146
152
|
}
|
|
153
|
+
|
|
154
|
+
createMetrics() {
|
|
155
|
+
this._metrics.getOrCreateMetric(NAMES.QUEUE_CAPACITY).recordValue(this.queue_size)
|
|
156
|
+
this._metrics.getOrCreateMetric(NAMES.QUEUE_SIZE).recordValue(this.spans.length)
|
|
157
|
+
}
|
|
147
158
|
}
|
|
148
159
|
|
|
149
160
|
module.exports = SpanStreamer
|
|
@@ -102,9 +102,21 @@ class StreamingSpanEvent {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
static fromSegment(segment, parentId = null, isRoot = false) {
|
|
105
|
+
const spanContext = segment.getSpanContext()
|
|
106
|
+
|
|
107
|
+
// Since segments already hold span agent attributes and we want to leverage
|
|
108
|
+
// filtering, we add to the segment attributes prior to processing.
|
|
109
|
+
if (spanContext.hasError && !segment.transaction.hasIgnoredErrorStatusCode()) {
|
|
110
|
+
const details = spanContext.errorDetails
|
|
111
|
+
segment.addSpanAttribute('error.message', details.message)
|
|
112
|
+
segment.addSpanAttribute('error.class', details.type)
|
|
113
|
+
if (details.expected) {
|
|
114
|
+
segment.addSpanAttribute('error.expected', details.expected)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
105
118
|
const agentAttributes = segment.attributes.get(DESTINATIONS.SPAN_EVENT)
|
|
106
119
|
|
|
107
|
-
const spanContext = segment.getSpanContext()
|
|
108
120
|
const customAttributes = spanContext.customAttributes.get(DESTINATIONS.SPAN_EVENT)
|
|
109
121
|
|
|
110
122
|
const transaction = segment.transaction
|
package/lib/timer.js
CHANGED
|
@@ -112,7 +112,7 @@ Timer.prototype.hasEnd = function hasEnd() {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
/*
|
|
115
|
-
* Sets duration and stops the timer, since the passed-in duration will take
|
|
115
|
+
* Sets duration and stops the timer, since the passed-in duration will take precedence
|
|
116
116
|
* over the measured duration.
|
|
117
117
|
* @param {number} duration The duration the timer should report.
|
|
118
118
|
*/
|
|
@@ -12,8 +12,8 @@ const DT_VERSION_MINOR = 1
|
|
|
12
12
|
|
|
13
13
|
module.exports = class DistributedTracePayload {
|
|
14
14
|
/**
|
|
15
|
-
* The class
|
|
16
|
-
* Created by calling {@link TransactionHandle#
|
|
15
|
+
* The class responsible for producing distributed trace payloads.
|
|
16
|
+
* Created by calling {@link TransactionHandle#_createDistributedTracePayload}.
|
|
17
17
|
*
|
|
18
18
|
* @constructor
|
|
19
19
|
*/
|