newrelic 6.7.0 → 6.10.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 +83 -0
- package/README.md +2 -0
- package/THIRD_PARTY_NOTICES.md +2 -0
- package/api.js +26 -12
- package/bin/run-versioned-tests.sh +10 -1
- package/bin/ssl.sh +3 -3
- package/lib/config/index.js +9 -0
- package/lib/errors/error-collector.js +30 -14
- package/lib/grpc/connection.js +60 -90
- package/lib/header-attributes.js +4 -0
- package/lib/instrumentation/core/http-outbound.js +3 -3
- package/lib/instrumentation/core/http.js +32 -14
- package/lib/metrics/normalizer.js +5 -5
- package/lib/prioritized-attributes.js +196 -0
- package/lib/serverless/aws-lambda.js +37 -4
- package/lib/serverless/event-sources.json +1 -1
- package/lib/shim/message-shim.js +16 -0
- package/lib/shim/shim.js +3 -3
- package/lib/spans/span-context.js +36 -0
- package/lib/spans/span-event.js +8 -1
- package/lib/spans/span-streamer.js +3 -2
- package/lib/spans/streaming-span-event-aggregator.js +11 -1
- package/lib/spans/streaming-span-event.js +7 -1
- package/lib/transaction/index.js +83 -15
- package/lib/transaction/trace/index.js +22 -0
- package/lib/transaction/trace/segment.js +28 -9
- package/lib/transaction/tracer/index.js +5 -0
- package/package.json +24 -9
- package/.eslintignore +0 -1
- package/.eslintrc.js +0 -67
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -5
- package/.travis.yml +0 -40
|
@@ -71,6 +71,13 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
71
71
|
const segment = tracer.createSegment(request.url, recordWeb)
|
|
72
72
|
segment.start()
|
|
73
73
|
|
|
74
|
+
if (request.method != null) {
|
|
75
|
+
segment.addSpanAttribute(
|
|
76
|
+
'request.method',
|
|
77
|
+
request.method
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
74
81
|
if (txInfo) {
|
|
75
82
|
// Seed segment stack to enable parenting logic leveraged by
|
|
76
83
|
// web framework instrumentations.
|
|
@@ -98,6 +105,11 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
98
105
|
transaction.url
|
|
99
106
|
)
|
|
100
107
|
|
|
108
|
+
segment.addSpanAttribute(
|
|
109
|
+
'request.uri',
|
|
110
|
+
transaction.url
|
|
111
|
+
)
|
|
112
|
+
|
|
101
113
|
// store the port on which this transaction runs
|
|
102
114
|
if (this.address instanceof Function) {
|
|
103
115
|
var address = this.address()
|
|
@@ -117,28 +129,30 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
117
129
|
transaction.queueTime = Date.now() - queueTimeStamp
|
|
118
130
|
}
|
|
119
131
|
|
|
132
|
+
const synthHeader = request.headers[NEWRELIC_SYNTHETICS_HEADER]
|
|
133
|
+
|
|
134
|
+
if (synthHeader && agent.config.trusted_account_ids && agent.config.encoding_key) {
|
|
135
|
+
handleSyntheticsHeader(
|
|
136
|
+
synthHeader,
|
|
137
|
+
agent.config.encoding_key,
|
|
138
|
+
agent.config.trusted_account_ids,
|
|
139
|
+
transaction
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
120
143
|
if (agent.config.distributed_tracing.enabled) {
|
|
121
144
|
// Node http headers are automatically lowercase
|
|
122
145
|
transaction.acceptDistributedTraceHeaders(transport, request.headers)
|
|
123
146
|
} else if (agent.config.cross_application_tracer.enabled) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
cat.handleCatHeaders(incomingCatId, obfTransaction, encKey, transaction)
|
|
147
|
+
const incomingCatId = request.headers[NEWRELIC_ID_HEADER]
|
|
148
|
+
const obfTransaction = request.headers[NEWRELIC_TRANSACTION_HEADER]
|
|
149
|
+
|
|
150
|
+
if (agent.config.encoding_key) {
|
|
151
|
+
cat.handleCatHeaders(incomingCatId, obfTransaction, agent.config.encoding_key, transaction)
|
|
130
152
|
if (transaction.incomingCatId) {
|
|
131
153
|
logger.trace('Got inbound request CAT headers in transaction %s',
|
|
132
154
|
transaction.id)
|
|
133
155
|
}
|
|
134
|
-
if (synthHeader && agent.config.trusted_account_ids) {
|
|
135
|
-
handleSyntheticsHeader(
|
|
136
|
-
synthHeader,
|
|
137
|
-
encKey,
|
|
138
|
-
agent.config.trusted_account_ids,
|
|
139
|
-
transaction
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
156
|
}
|
|
143
157
|
}
|
|
144
158
|
|
|
@@ -170,6 +184,8 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
170
184
|
'http.statusCode',
|
|
171
185
|
responseCode
|
|
172
186
|
)
|
|
187
|
+
|
|
188
|
+
segment.addSpanAttribute('http.statusCode', responseCode)
|
|
173
189
|
|
|
174
190
|
/*
|
|
175
191
|
TODO: remove with next major release
|
|
@@ -190,6 +206,8 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
|
|
|
190
206
|
response.statusMessage
|
|
191
207
|
)
|
|
192
208
|
|
|
209
|
+
segment.addSpanAttribute('http.statusText', response.statusMessage)
|
|
210
|
+
|
|
193
211
|
/*
|
|
194
212
|
TODO: remove with next major release
|
|
195
213
|
httpResponseMessage attribute is deprecated
|
|
@@ -4,7 +4,7 @@ var EventEmitter = require('events').EventEmitter
|
|
|
4
4
|
var util = require('util')
|
|
5
5
|
var logger = require('../logger').child({component: 'metric_normalizer'})
|
|
6
6
|
var deepEqual = require('../util/deep-equal')
|
|
7
|
-
var
|
|
7
|
+
var NormalizerRule = require('./normalizer/rule')
|
|
8
8
|
var NAMES = require('../metrics/names.js')
|
|
9
9
|
|
|
10
10
|
|
|
@@ -82,7 +82,7 @@ MetricNormalizer.prototype.load = function load(json) {
|
|
|
82
82
|
|
|
83
83
|
json.forEach(function cb_forEach(ruleJSON) {
|
|
84
84
|
// no need to add the same rule twice
|
|
85
|
-
var rule = new
|
|
85
|
+
var rule = new NormalizerRule(ruleJSON)
|
|
86
86
|
if (!this.rules.find(deepEqual.bind(null, rule))) {
|
|
87
87
|
this.rules.push(rule)
|
|
88
88
|
logger.trace("Loaded %s normalization rule: %s", this.type, rule)
|
|
@@ -142,9 +142,9 @@ MetricNormalizer.prototype.loadFromConfig = function loadFromConfig() {
|
|
|
142
142
|
: r.precedence > json.eval_order
|
|
143
143
|
})
|
|
144
144
|
if (insert === -1) {
|
|
145
|
-
this.rules.push(new
|
|
145
|
+
this.rules.push(new NormalizerRule(json))
|
|
146
146
|
} else {
|
|
147
|
-
this.rules.splice(insert, 0, new
|
|
147
|
+
this.rules.splice(insert, 0, new NormalizerRule(json))
|
|
148
148
|
}
|
|
149
149
|
}, this)
|
|
150
150
|
}
|
|
@@ -186,7 +186,7 @@ MetricNormalizer.prototype.addSimple = function addSimple(pattern, name) {
|
|
|
186
186
|
json.ignore = true
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
this.rules.unshift(new
|
|
189
|
+
this.rules.unshift(new NormalizerRule(json))
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
/**
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Config = require('./config')
|
|
4
|
+
const logger = require('./logger').child({component: 'attributes'})
|
|
5
|
+
const isValidType = require('./util/attribute-types')
|
|
6
|
+
const byteUtils = require('./util/byte-limit')
|
|
7
|
+
const properties = require('./util/properties')
|
|
8
|
+
|
|
9
|
+
const ATTRIBUTE_PRIORITY = {
|
|
10
|
+
HIGH: Infinity,
|
|
11
|
+
LOW: -Infinity
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class PrioritizedAttributes {
|
|
15
|
+
constructor(scope, limit = Infinity) {
|
|
16
|
+
this.filter = makeFilter(scope)
|
|
17
|
+
this.limit = limit
|
|
18
|
+
|
|
19
|
+
this.attributes = new Map()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
isValidLength(str) {
|
|
24
|
+
return typeof str === 'number' || byteUtils.isValidLength(str, 255)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
_set(destinations, key, value, truncateExempt, priority) {
|
|
28
|
+
this.attributes.set(key, {value, destinations, truncateExempt, priority})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get(dest) {
|
|
32
|
+
const attrs = Object.create(null)
|
|
33
|
+
|
|
34
|
+
for (let [key, attr] of this.attributes) {
|
|
35
|
+
if (!(attr.destinations & dest)) {
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
attrs[key] = typeof attr.value === 'string' && !attr.truncateExempt
|
|
40
|
+
? byteUtils.truncate(attr.value, 255)
|
|
41
|
+
: attr.value
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return attrs
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
has(key) {
|
|
48
|
+
this.attributes.has(key)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
reset() {
|
|
52
|
+
this.attributes = new Map()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
addAttribute(
|
|
56
|
+
destinations,
|
|
57
|
+
key,
|
|
58
|
+
value,
|
|
59
|
+
truncateExempt = false,
|
|
60
|
+
priority = ATTRIBUTE_PRIORITY.HIGH
|
|
61
|
+
) {
|
|
62
|
+
const existingAttribute = this.attributes.get(key)
|
|
63
|
+
|
|
64
|
+
let droppableAttributeKey = null
|
|
65
|
+
if (!existingAttribute && this.attributes.size === this.limit) {
|
|
66
|
+
droppableAttributeKey = this._getDroppableAttributeKey(priority)
|
|
67
|
+
|
|
68
|
+
if (!droppableAttributeKey) {
|
|
69
|
+
logger.debug(
|
|
70
|
+
`Maximum number of custom attributes have been added.
|
|
71
|
+
Dropping attribute ${key} with ${value} type.`
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (existingAttribute && priority < existingAttribute.priority) {
|
|
79
|
+
logger.debug('incoming priority for \'%s\' is lower than existing, not updating.', key)
|
|
80
|
+
logger.trace(
|
|
81
|
+
'%s attribute retained value: %s, ignored value: %s',
|
|
82
|
+
key,
|
|
83
|
+
existingAttribute.value,
|
|
84
|
+
value
|
|
85
|
+
)
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!isValidType(value)) {
|
|
90
|
+
logger.debug(
|
|
91
|
+
'Not adding attribute %s with %s value type. This is expected for undefined' +
|
|
92
|
+
'attributes and only an issue if an attribute is not expected to be undefined' +
|
|
93
|
+
'or not of the type expected.',
|
|
94
|
+
key,
|
|
95
|
+
typeof value
|
|
96
|
+
)
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!this.isValidLength(key)) {
|
|
101
|
+
logger.warn(
|
|
102
|
+
'Length limit exceeded for attribute name, not adding: %s',
|
|
103
|
+
key
|
|
104
|
+
)
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
// Only set the attribute if at least one destination passed
|
|
110
|
+
const validDestinations = this.filter(destinations, key)
|
|
111
|
+
if (!validDestinations) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (droppableAttributeKey) {
|
|
116
|
+
logger.trace(
|
|
117
|
+
'dropping existing lower priority attribute %s ' +
|
|
118
|
+
'to add higher priority attribute %s',
|
|
119
|
+
droppableAttributeKey,
|
|
120
|
+
key
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
this.attributes.delete(droppableAttributeKey)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this._set(validDestinations, key, value, truncateExempt, priority)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
addAttributes(destinations, attrs) {
|
|
130
|
+
for (let key in attrs) {
|
|
131
|
+
if (properties.hasOwn(attrs, key)) {
|
|
132
|
+
this.addAttribute(destinations, key, attrs[key])
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
_getDroppableAttributeKey(incomingPriority) {
|
|
138
|
+
// There will never be anything lower priority to drop
|
|
139
|
+
if (incomingPriority === ATTRIBUTE_PRIORITY.LOW) {
|
|
140
|
+
return null
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this.lastFoundIndexCache = this.lastFoundIndexCache || Object.create(null)
|
|
144
|
+
const lastFoundIndex = this.lastFoundIndexCache[incomingPriority]
|
|
145
|
+
|
|
146
|
+
// We've already dropped all items lower than incomingPriority.
|
|
147
|
+
// We can honor the cache because at the point by which we've dropped
|
|
148
|
+
// all lower priority items, due to being at max capacity, there will never be another
|
|
149
|
+
// lower-priority item added. Lower priority items are unable to drop higher priority items.
|
|
150
|
+
if (lastFoundIndex === -1) {
|
|
151
|
+
return null
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// We can't reverse iterate w/o creating an array that will iterate,
|
|
155
|
+
// so we just iterate forward stopping once we've checked the last cached index.
|
|
156
|
+
let lowerPriorityAttributeName = null
|
|
157
|
+
let foundIndex = -1
|
|
158
|
+
|
|
159
|
+
let index = 0
|
|
160
|
+
for (const [key, attribute] of this.attributes) {
|
|
161
|
+
// Don't search past last found lower priority item.
|
|
162
|
+
// At the point of dropping items for this priority,
|
|
163
|
+
// lower priority items will never be added.
|
|
164
|
+
if (lastFoundIndex && index > lastFoundIndex) {
|
|
165
|
+
break
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (attribute.priority < incomingPriority) {
|
|
169
|
+
lowerPriorityAttributeName = key
|
|
170
|
+
foundIndex = index
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
index++
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Item may not get dropped, so we simply store the index as
|
|
177
|
+
// an upper maximum and allow a future pass to clear out.
|
|
178
|
+
this.lastFoundIndexCache[incomingPriority] = foundIndex
|
|
179
|
+
|
|
180
|
+
return lowerPriorityAttributeName
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function makeFilter(scope) {
|
|
185
|
+
const {attributeFilter} = Config.getInstance()
|
|
186
|
+
if (scope === 'transaction') {
|
|
187
|
+
return (d, k) => attributeFilter.filterTransaction(d, k)
|
|
188
|
+
} else if (scope === 'segment') {
|
|
189
|
+
return (d, k) => attributeFilter.filterSegment(d, k)
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
module.exports = {
|
|
194
|
+
PrioritizedAttributes: PrioritizedAttributes,
|
|
195
|
+
ATTRIBUTE_PRIORITY: ATTRIBUTE_PRIORITY
|
|
196
|
+
}
|
|
@@ -121,7 +121,10 @@ class AwsLambda {
|
|
|
121
121
|
transaction.setPartialName(transactionName)
|
|
122
122
|
|
|
123
123
|
const isApiGatewayLambdaProxy = apiGateway.isLambdaProxyEvent(event)
|
|
124
|
-
|
|
124
|
+
const segmentRecorder = isApiGatewayLambdaProxy ? recordWeb : recordBackground
|
|
125
|
+
const segment = shim.createSegment(functionName, segmentRecorder)
|
|
126
|
+
transaction.baseSegment = segment
|
|
127
|
+
|
|
125
128
|
// resultProcessor is used to execute additional logic based on the
|
|
126
129
|
// payload supplied to the callback.
|
|
127
130
|
let resultProcessor
|
|
@@ -131,9 +134,6 @@ class AwsLambda {
|
|
|
131
134
|
resultProcessor = getApiGatewayLambdaProxyResultProcessor(transaction)
|
|
132
135
|
}
|
|
133
136
|
|
|
134
|
-
const segmentRecorder = isApiGatewayLambdaProxy ? recordWeb : recordBackground
|
|
135
|
-
const segment = shim.createSegment(functionName, segmentRecorder)
|
|
136
|
-
transaction.baseSegment = segment
|
|
137
137
|
|
|
138
138
|
const cbIndex = args.length - 1
|
|
139
139
|
|
|
@@ -175,6 +175,8 @@ class AwsLambda {
|
|
|
175
175
|
shim.agent.setLambdaArn(context.invokedFunctionArn)
|
|
176
176
|
|
|
177
177
|
shim.agent.setLambdaFunctionVersion(context.functionVersion)
|
|
178
|
+
|
|
179
|
+
segment.addSpanAttributes(awsAttributes)
|
|
178
180
|
|
|
179
181
|
segment.start()
|
|
180
182
|
|
|
@@ -301,6 +303,8 @@ function getApiGatewayLambdaProxyResultProcessor(transaction) {
|
|
|
301
303
|
function setWebRequest(shim, transaction, request) {
|
|
302
304
|
transaction.type = shim.WEB
|
|
303
305
|
|
|
306
|
+
const segment = transaction.baseSegment
|
|
307
|
+
|
|
304
308
|
transaction.url = urltils.scrub(request.url.path)
|
|
305
309
|
transaction.verb = request.method
|
|
306
310
|
transaction.trace.attributes.addAttribute(
|
|
@@ -308,6 +312,12 @@ function setWebRequest(shim, transaction, request) {
|
|
|
308
312
|
'request.method',
|
|
309
313
|
request.method
|
|
310
314
|
)
|
|
315
|
+
|
|
316
|
+
segment.addSpanAttribute(
|
|
317
|
+
'request.method',
|
|
318
|
+
request.method
|
|
319
|
+
)
|
|
320
|
+
|
|
311
321
|
transaction.port = request.url.port
|
|
312
322
|
|
|
313
323
|
transaction.addRequestParameters(request.url.requestParameters)
|
|
@@ -319,6 +329,11 @@ function setWebRequest(shim, transaction, request) {
|
|
|
319
329
|
request.url.path
|
|
320
330
|
)
|
|
321
331
|
|
|
332
|
+
segment.addSpanAttribute(
|
|
333
|
+
'request.uri',
|
|
334
|
+
request.url.path
|
|
335
|
+
)
|
|
336
|
+
|
|
322
337
|
headerAttributes.collectRequestHeaders(request.headers, transaction)
|
|
323
338
|
|
|
324
339
|
if (shim.agent.config.distributed_tracing.enabled) {
|
|
@@ -369,6 +384,10 @@ function setWebResponse(transaction, response) {
|
|
|
369
384
|
transaction.statusCode = response.statusCode
|
|
370
385
|
|
|
371
386
|
const responseCode = String(response.statusCode)
|
|
387
|
+
/*
|
|
388
|
+
TODO: remove with next major release
|
|
389
|
+
httpResponseCode attribute is deprecated
|
|
390
|
+
*/
|
|
372
391
|
transaction.trace.attributes.addAttribute(
|
|
373
392
|
ATTR_DEST.TRANS_COMMON,
|
|
374
393
|
'httpResponseCode',
|
|
@@ -376,10 +395,24 @@ function setWebResponse(transaction, response) {
|
|
|
376
395
|
)
|
|
377
396
|
|
|
378
397
|
if (/^\d+$/.test(responseCode)) {
|
|
398
|
+
/*
|
|
399
|
+
TODO: remove with next major release
|
|
400
|
+
response.status attribute is deprecated
|
|
401
|
+
*/
|
|
379
402
|
transaction.trace.attributes.addAttribute(
|
|
380
403
|
ATTR_DEST.TRANS_COMMON,
|
|
381
404
|
'response.status',
|
|
382
405
|
responseCode)
|
|
406
|
+
|
|
407
|
+
transaction.trace.attributes.addAttribute(
|
|
408
|
+
ATTR_DEST.TRANS_COMMON,
|
|
409
|
+
'http.statusCode',
|
|
410
|
+
responseCode
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
const segment = transaction.agent.tracer.getSegment()
|
|
414
|
+
|
|
415
|
+
segment.addSpanAttribute('http.statusCode', responseCode)
|
|
383
416
|
}
|
|
384
417
|
|
|
385
418
|
headerAttributes.collectResponseHeaders(response.headers, transaction)
|
package/lib/shim/message-shim.js
CHANGED
|
@@ -750,6 +750,12 @@ function recordSubscribedConsume(nodule, properties, spec) {
|
|
|
750
750
|
ATTR_DESTS.NONE,
|
|
751
751
|
'message.parameters.' + key,
|
|
752
752
|
msgDesc.parameters[key])
|
|
753
|
+
|
|
754
|
+
tx.baseSegment.attributes.addAttribute(
|
|
755
|
+
ATTR_DESTS.NONE,
|
|
756
|
+
'message.parameters.' + key,
|
|
757
|
+
msgDesc.parameters[key]
|
|
758
|
+
)
|
|
753
759
|
}
|
|
754
760
|
}
|
|
755
761
|
|
|
@@ -762,6 +768,11 @@ function recordSubscribedConsume(nodule, properties, spec) {
|
|
|
762
768
|
'message.routingKey',
|
|
763
769
|
msgDesc.routingKey
|
|
764
770
|
)
|
|
771
|
+
|
|
772
|
+
tx.baseSegment.addSpanAttribute(
|
|
773
|
+
'message.routingKey',
|
|
774
|
+
msgDesc.routingKey
|
|
775
|
+
)
|
|
765
776
|
}
|
|
766
777
|
if (shim.isString(msgDesc.queue)) {
|
|
767
778
|
tx.trace.attributes.addAttribute(
|
|
@@ -769,6 +780,11 @@ function recordSubscribedConsume(nodule, properties, spec) {
|
|
|
769
780
|
'message.queueName',
|
|
770
781
|
msgDesc.queue
|
|
771
782
|
)
|
|
783
|
+
|
|
784
|
+
tx.baseSegment.addSpanAttribute(
|
|
785
|
+
'message.queueName',
|
|
786
|
+
msgDesc.queue
|
|
787
|
+
)
|
|
772
788
|
}
|
|
773
789
|
}
|
|
774
790
|
if (msgDesc.headers) {
|
package/lib/shim/shim.js
CHANGED
|
@@ -989,9 +989,9 @@ function record(nodule, properties, recordNamer) {
|
|
|
989
989
|
})
|
|
990
990
|
|
|
991
991
|
// Apply the function, and (if it returned a stream) bind that too.
|
|
992
|
-
//
|
|
993
|
-
//
|
|
994
|
-
//
|
|
992
|
+
// The reason there is no check for `segment` is because it should
|
|
993
|
+
// be guaranteed by the parent and active transaction check
|
|
994
|
+
// at the beginning of this function.
|
|
995
995
|
var ret = _applyRecorderSegment(segment, this, args, segDesc)
|
|
996
996
|
if (ret) {
|
|
997
997
|
if (segDesc.stream) {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {MAXIMUM_CUSTOM_ATTRIBUTES} = require('../attributes')
|
|
4
|
+
const {PrioritizedAttributes, ATTRIBUTE_PRIORITY} = require('../prioritized-attributes')
|
|
5
|
+
const {DESTINATIONS} = require('../config/attribute-filter')
|
|
6
|
+
|
|
7
|
+
// Scoping impacts memoization. We could decide to add a scope instead of including
|
|
8
|
+
// spans in segment scope in the future.
|
|
9
|
+
const ATTRIBUTE_SCOPE = 'segment'
|
|
10
|
+
|
|
11
|
+
class SpanContext {
|
|
12
|
+
constructor(intrinsicAttributes, customAttributes) {
|
|
13
|
+
this.intrinsicAttributes = intrinsicAttributes || Object.create(null)
|
|
14
|
+
|
|
15
|
+
this.customAttributes =
|
|
16
|
+
customAttributes || new PrioritizedAttributes(ATTRIBUTE_SCOPE, MAXIMUM_CUSTOM_ATTRIBUTES)
|
|
17
|
+
|
|
18
|
+
this.ATTRIBUTE_PRIORITY = ATTRIBUTE_PRIORITY
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
addIntrinsicAttribute(key, value) {
|
|
22
|
+
this.intrinsicAttributes[key] = value
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
addCustomAttribute(key, value, priority) {
|
|
26
|
+
this.customAttributes.addAttribute(
|
|
27
|
+
DESTINATIONS.SPAN_EVENT,
|
|
28
|
+
key,
|
|
29
|
+
value,
|
|
30
|
+
false,
|
|
31
|
+
priority
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = SpanContext
|
package/lib/spans/span-event.js
CHANGED
|
@@ -80,7 +80,9 @@ class SpanEvent {
|
|
|
80
80
|
*/
|
|
81
81
|
static fromSegment(segment, parentId = null, isRoot = false) {
|
|
82
82
|
const attributes = segment.attributes.get(DESTINATIONS.SPAN_EVENT)
|
|
83
|
-
|
|
83
|
+
|
|
84
|
+
const spanContext = segment.getSpanContext()
|
|
85
|
+
const customAttributes = spanContext.customAttributes.get(DESTINATIONS.SPAN_EVENT)
|
|
84
86
|
|
|
85
87
|
let span = null
|
|
86
88
|
if (HttpSpanEvent.testSegment(segment)) {
|
|
@@ -91,6 +93,11 @@ class SpanEvent {
|
|
|
91
93
|
span = new SpanEvent(attributes, customAttributes)
|
|
92
94
|
}
|
|
93
95
|
|
|
96
|
+
|
|
97
|
+
for (const [key, value] of Object.entries(spanContext.intrinsicAttributes)) {
|
|
98
|
+
span.intrinsics[key] = value
|
|
99
|
+
}
|
|
100
|
+
|
|
94
101
|
const tx = segment.transaction
|
|
95
102
|
|
|
96
103
|
span.intrinsics.traceId = tx.traceId
|
|
@@ -126,10 +126,11 @@ class SpanStreamer {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
connect(agent_run_id) {
|
|
129
|
+
connect(agent_run_id, requestHeadersMap) {
|
|
130
130
|
this.connection.setConnectionDetails(
|
|
131
131
|
this.license_key,
|
|
132
|
-
agent_run_id
|
|
132
|
+
agent_run_id,
|
|
133
|
+
requestHeadersMap
|
|
133
134
|
)
|
|
134
135
|
|
|
135
136
|
this.connection.connectSpans()
|
|
@@ -31,8 +31,10 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
logger.trace('StreamingSpanEventAggregator starting up')
|
|
34
|
-
this.stream.connect(this.runId)
|
|
34
|
+
this.stream.connect(this.runId, this.requestHeadersMap)
|
|
35
35
|
this.started = true
|
|
36
|
+
|
|
37
|
+
this.emit('started')
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
stop() {
|
|
@@ -43,6 +45,8 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
43
45
|
logger.trace('StreamingSpanEventAggregator stopping')
|
|
44
46
|
this.stream.disconnect()
|
|
45
47
|
this.started = false
|
|
48
|
+
|
|
49
|
+
this.emit('stopped')
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
send() {
|
|
@@ -83,6 +87,12 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
83
87
|
const span = StreamingSpanEvent.fromSegment(segment, parentId, isRoot)
|
|
84
88
|
this.stream.write(span)
|
|
85
89
|
}
|
|
90
|
+
|
|
91
|
+
reconfigure(config) {
|
|
92
|
+
super.reconfigure(config)
|
|
93
|
+
|
|
94
|
+
this.requestHeadersMap = config.request_headers_map
|
|
95
|
+
}
|
|
86
96
|
}
|
|
87
97
|
|
|
88
98
|
module.exports = StreamingSpanEventAggregator
|
|
@@ -98,7 +98,9 @@ class StreamingSpanEvent {
|
|
|
98
98
|
|
|
99
99
|
static fromSegment(segment, parentId = null, isRoot = false) {
|
|
100
100
|
const agentAttributes = segment.attributes.get(DESTINATIONS.SPAN_EVENT)
|
|
101
|
-
|
|
101
|
+
|
|
102
|
+
const spanContext = segment.getSpanContext()
|
|
103
|
+
const customAttributes = spanContext.customAttributes.get(DESTINATIONS.SPAN_EVENT)
|
|
102
104
|
|
|
103
105
|
const transaction = segment.transaction
|
|
104
106
|
const traceId = transaction.traceId
|
|
@@ -112,6 +114,10 @@ class StreamingSpanEvent {
|
|
|
112
114
|
span = new StreamingSpanEvent(traceId, agentAttributes, customAttributes)
|
|
113
115
|
}
|
|
114
116
|
|
|
117
|
+
for (const [key, value] of Object.entries(spanContext.intrinsicAttributes)) {
|
|
118
|
+
span.addIntrinsicAttribute(key, value)
|
|
119
|
+
}
|
|
120
|
+
|
|
115
121
|
span.addIntrinsicAttribute('guid', segment.id)
|
|
116
122
|
span.addIntrinsicAttribute('parentId', parentId)
|
|
117
123
|
span.addIntrinsicAttribute('transactionId', transaction.id)
|