newrelic 6.3.0 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/{.eslintrc → .eslintrc.js} +4 -2
  2. package/.travis.yml +0 -1
  3. package/NEWS.md +136 -0
  4. package/README.md +1 -0
  5. package/api.js +75 -4
  6. package/bin/publish-docs.sh +1 -1
  7. package/bin/travis-node.sh +4 -1
  8. package/index.js +3 -3
  9. package/lib/aggregators/base-aggregator.js +1 -1
  10. package/lib/attributes.js +15 -6
  11. package/lib/config/default.js +11 -1
  12. package/lib/config/env.js +3 -1
  13. package/lib/config/hsm.js +6 -1
  14. package/lib/config/index.js +29 -8
  15. package/lib/config/lasp.js +16 -1
  16. package/lib/errors/error-collector.js +51 -90
  17. package/lib/errors/helper.js +13 -13
  18. package/lib/errors/index.js +36 -18
  19. package/lib/feature_flags.js +3 -3
  20. package/lib/header-processing.js +75 -0
  21. package/lib/instrumentation/core/child_process.js +12 -0
  22. package/lib/instrumentation/core/http-outbound.js +6 -28
  23. package/lib/instrumentation/core/http.js +100 -170
  24. package/lib/instrumentation/hapi/hapi-17.js +10 -3
  25. package/lib/metrics/names.js +1 -0
  26. package/lib/serverless/aws-lambda.js +79 -33
  27. package/lib/serverless/event-sources.json +128 -0
  28. package/lib/shim/transaction-shim.js +10 -33
  29. package/lib/spans/span-event-aggregator.js +2 -2
  30. package/lib/spans/span-event.js +33 -11
  31. package/lib/transaction/handle.js +73 -4
  32. package/lib/transaction/index.js +182 -34
  33. package/lib/transaction/trace/index.js +6 -5
  34. package/lib/transaction/trace/segment.js +12 -1
  35. package/lib/transaction/tracecontext.js +409 -163
  36. package/lib/util/get.js +16 -0
  37. package/lib/util/hashes.js +55 -6
  38. package/package.json +8 -10
  39. package/stub_api.js +5 -0
@@ -12,10 +12,7 @@ const urltils = require('../../util/urltils')
12
12
  const properties = require('../../util/properties')
13
13
  const psemver = require('../../util/process-version')
14
14
  const headerAttributes = require('../../header-attributes')
15
- const TRACE_CONTEXT_PARENT_HEADER
16
- = require('../../transaction/tracecontext').TRACE_CONTEXT_PARENT_HEADER
17
- const TRACE_CONTEXT_STATE_HEADER
18
- = require('../../transaction/tracecontext').TRACE_CONTEXT_STATE_HEADER
15
+ const headerProcessing = require('../../header-processing')
19
16
 
20
17
  const NAMES = require('../../metrics/names')
21
18
  const DESTS = require('../../config/attribute-filter').DESTINATIONS
@@ -26,15 +23,12 @@ const DESTS = require('../../config/attribute-filter').DESTINATIONS
26
23
  *
27
24
  */
28
25
  const SHOULD_WRAP_HTTPS = psemver.satisfies('>=9.0.0 || 8.9.0')
26
+ const SHOULD_FORMAT_ARGS = psemver.satisfies('>=10.0.0')
29
27
  const NR_CONNECTION_PROP = '__NR__connection'
30
- const REQUEST_HEADER = 'x-request-start'
31
- const QUEUE_HEADER = 'x-queue-start'
32
28
  const NEWRELIC_ID_HEADER = 'x-newrelic-id'
33
29
  const NEWRELIC_APP_DATA_HEADER = 'x-newrelic-app-data'
34
- const NEWRELIC_TRACE_HEADER = 'newrelic'
35
30
  const NEWRELIC_TRANSACTION_HEADER = 'x-newrelic-transaction'
36
31
  const NEWRELIC_SYNTHETICS_HEADER = 'x-newrelic-synthetics'
37
- const CONTENT_LENGTH_REGEX = /^Content-Length$/i
38
32
  const TRANSACTION_INFO_KEY = '__NR_transactionInfo'
39
33
 
40
34
 
@@ -118,57 +112,14 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
118
112
  'Applying user naming rules for RUM.')
119
113
  transaction.applyUserNamingRules(request.url)
120
114
 
121
- /**
122
- * Calculate Queue Time
123
- *
124
- * Queue time is provided by certain providers by stamping the request
125
- * header with the time the request arrived at the router.
126
- *
127
- * Units for queue time are
128
- */
129
- var qtime = request.headers[REQUEST_HEADER] || request.headers[QUEUE_HEADER]
130
- if (qtime) {
131
- var split = qtime.split('=')
132
- if (split.length > 1) {
133
- qtime = split[1]
134
- }
135
-
136
- var start = parseFloat(qtime)
137
-
138
- if (isNaN(start)) {
139
- logger.warn('Queue time header parsed as NaN (%s)', qtime)
140
- } else {
141
- // nano seconds
142
- if (start > 1e18) start = start / 1e6
143
- // micro seconds
144
- else if (start > 1e15) start = start / 1e3
145
- // seconds
146
- else if (start < 1e12) start = start * 1e3
147
-
148
- transaction.queueTime = Date.now() - start
149
- }
115
+ const queueTimeStamp = headerProcessing.getQueueTime(logger, request.headers)
116
+ if (queueTimeStamp) {
117
+ transaction.queueTime = Date.now() - queueTimeStamp
150
118
  }
119
+
151
120
  if (agent.config.distributed_tracing.enabled) {
152
- if (agent.config.feature_flag.dt_format_w3c) {
153
- const traceparent = request.headers[TRACE_CONTEXT_PARENT_HEADER]
154
- const tracestate = request.headers[TRACE_CONTEXT_STATE_HEADER]
155
- if (traceparent && tracestate) {
156
- logger.trace(
157
- 'Accepting trace context payload for transaction %s',
158
- transaction.id
159
- )
160
- transaction.traceContext.acceptTraceContextPayload(traceparent, tracestate)
161
- }
162
- } else {
163
- const payload = request.headers[NEWRELIC_TRACE_HEADER]
164
- if (payload) {
165
- logger.trace(
166
- 'Accepting distributed trace payload for transaction %s',
167
- transaction.id
168
- )
169
- transaction.acceptDistributedTracePayload(payload, transport)
170
- }
171
- }
121
+ // Node http headers are automatically lowercase
122
+ transaction.acceptDistributedTraceHeaders(transport, request.headers)
172
123
  } else if (agent.config.cross_application_tracer.enabled) {
173
124
  var encKey = agent.config.encoding_key
174
125
  var incomingCatId = request.headers[NEWRELIC_ID_HEADER]
@@ -202,6 +153,10 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
202
153
 
203
154
  if (response) {
204
155
  if (response.statusCode != null) {
156
+ /*
157
+ TODO: remove with next major release
158
+ httpResponseCode attribute is deprecated
159
+ */
205
160
  var responseCode = String(response.statusCode)
206
161
  transaction.trace.attributes.addAttribute(
207
162
  DESTS.TRANS_COMMON,
@@ -210,6 +165,16 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
210
165
  )
211
166
 
212
167
  if (/^\d+$/.test(responseCode)) {
168
+ transaction.trace.attributes.addAttribute(
169
+ DESTS.TRANS_COMMON,
170
+ 'http.statusCode',
171
+ responseCode
172
+ )
173
+
174
+ /*
175
+ TODO: remove with next major release
176
+ response.status attribute is deprecated
177
+ */
213
178
  transaction.trace.attributes.addAttribute(
214
179
  DESTS.TRANS_COMMON,
215
180
  'response.status',
@@ -217,7 +182,18 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
217
182
  )
218
183
  }
219
184
  }
185
+
220
186
  if (response.statusMessage !== undefined) {
187
+ transaction.trace.attributes.addAttribute(
188
+ DESTS.TRANS_COMMON,
189
+ 'http.statusText',
190
+ response.statusMessage
191
+ )
192
+
193
+ /*
194
+ TODO: remove with next major release
195
+ httpResponseMessage attribute is deprecated
196
+ */
221
197
  transaction.trace.attributes.addAttribute(
222
198
  DESTS.TRANS_COMMON,
223
199
  'httpResponseMessage',
@@ -225,8 +201,7 @@ function wrapEmitWithTransaction(agent, emit, isHTTPS) {
225
201
  )
226
202
  }
227
203
 
228
- // TODO: Just use `getHeaders()` after deprecating Node <7.7.
229
- var headers = (response.getHeaders && response.getHeaders()) || response._headers
204
+ var headers = response.getHeaders()
230
205
  if (headers) {
231
206
  headerAttributes.collectResponseHeaders(headers, transaction)
232
207
  }
@@ -379,25 +354,12 @@ function wrapWriteHead(agent, writeHead) {
379
354
  var new_headers = arguments[arguments.length - 1]
380
355
 
381
356
  if (typeof new_headers === 'object') {
382
- for (var header in new_headers) { // jshint ignore: line
383
- if (CONTENT_LENGTH_REGEX.test(header)) {
384
- contentLength = new_headers[header]
385
- break
386
- }
387
- }
357
+ contentLength = headerProcessing.getContentLengthFromHeaders(new_headers)
388
358
  }
389
359
 
390
- if (contentLength === -1 && this._headers) {
391
- // JSHint complains about ownProperty stuff, but since we are looking
392
- // for a specific name that doesn't matter so I'm disabling it.
393
- // Outbound headers can be capitalized in any way, use regex instead
394
- // of direct lookup.
395
- for (var userHeader in this._headers) { // jshint ignore: line
396
- if (CONTENT_LENGTH_REGEX.test(userHeader)) {
397
- contentLength = this._headers[userHeader]
398
- break
399
- }
400
- }
360
+ const currentHeaders = this.getHeaders()
361
+ if (contentLength === -1 && currentHeaders) {
362
+ contentLength = headerProcessing.getContentLengthFromHeaders(currentHeaders)
401
363
  }
402
364
  // Stored on the tx so we can push a metric with this time instead of
403
365
  // actual duration.
@@ -434,8 +396,60 @@ function wrapWriteHead(agent, writeHead) {
434
396
  }
435
397
  }
436
398
 
399
+ // Taken from the Node code base, internal/url.js
400
+ function urlToOptions(_url) {
401
+ const options = {
402
+ protocol: _url.protocol,
403
+ hostname: typeof _url.hostname === 'string' && _url.hostname.startsWith('[') ?
404
+ _url.hostname.slice(1, -1) :
405
+ _url.hostname,
406
+ hash: _url.hash,
407
+ search: _url.search,
408
+ pathname: _url.pathname,
409
+ path: `${_url.pathname || ''}${_url.search || ''}`,
410
+ href: _url.href
411
+ }
412
+ if (_url.port !== '') {
413
+ options.port = Number(_url.port)
414
+ }
415
+ if (_url.username || _url.password) {
416
+ options.auth = `${_url.username}:${_url.password}`
417
+ }
418
+ return options
419
+ }
420
+
437
421
  function wrapRequest(agent, request) {
438
- return function wrappedRequest(options) {
422
+ // URL as a global was not added until Node v10
423
+ const URLClass = global.URL ? global.URL : url.URL
424
+ return function wrappedRequest(input, options, cb) {
425
+ let reqArgs = arguments
426
+ if (SHOULD_FORMAT_ARGS) {
427
+ // Support new function signatures in Node v10+. If the first argument is a URL,
428
+ // merge it into the options object. This code is copied from Node internals.
429
+ if (typeof input === 'string') {
430
+ const urlStr = input
431
+ input = urlToOptions(new URLClass(urlStr))
432
+ } else if (input.constructor && input.constructor.name === 'URL') {
433
+ input = urlToOptions(input)
434
+ } else {
435
+ cb = options
436
+ options = input
437
+ input = null
438
+ }
439
+
440
+ if (typeof options === 'function') {
441
+ cb = options
442
+ options = input || {}
443
+ } else {
444
+ options = Object.assign(input || {}, options)
445
+ }
446
+
447
+ reqArgs = [options, cb]
448
+ } else {
449
+ // Node v8 function signature had options as the first argument
450
+ options = input
451
+ }
452
+
439
453
  // Don't pollute metrics and calls with NR connections
440
454
  const internalOnly = options && options[NR_CONNECTION_PROP]
441
455
  if (internalOnly) {
@@ -453,13 +467,12 @@ function wrapRequest(agent, request) {
453
467
  logOpts.port
454
468
  )
455
469
  }
456
- return request.apply(this, arguments)
470
+ return request.apply(this, reqArgs)
457
471
  }
458
472
 
459
- const args = agent.tracer.slice(arguments)
473
+ const args = agent.tracer.slice(reqArgs)
460
474
  const context = this
461
475
 
462
- // hostname & port logic pulled directly from node's 0.10 lib/http.js
463
476
  return instrumentOutbound(agent, options, function makeRequest(opts) {
464
477
  args[0] = opts
465
478
  return request.apply(context, args)
@@ -467,28 +480,6 @@ function wrapRequest(agent, request) {
467
480
  }
468
481
  }
469
482
 
470
- function wrapLegacyRequest(agent, request) {
471
- return function wrappedLegacyRequest(method, path, headers) {
472
- var makeRequest = request.bind(this, method, path, headers)
473
-
474
- if (agent.tracer.getTransaction()) {
475
- return instrumentOutbound(agent, this, makeRequest)
476
- }
477
-
478
- logger.trace('No transaction, not recording external to %s:%s', this.host, this.port)
479
- return makeRequest()
480
- }
481
- }
482
-
483
- function wrapLegacyClient(agent, proto) {
484
- shimmer.wrapMethod(
485
- proto,
486
- 'http.Client.prototype',
487
- 'request',
488
- wrapLegacyRequest.bind(null, agent)
489
- )
490
- }
491
-
492
483
  module.exports = function initialize(agent, http, moduleName) {
493
484
  if (!http) {
494
485
  logger.debug('Did not get http module, not instrumenting!')
@@ -545,7 +536,7 @@ module.exports = function initialize(agent, http, moduleName) {
545
536
  // change originally also appeared in 8.9.0 but was reverted in 8.9.1.
546
537
  //
547
538
  // TODO: Remove `SHOULD_WRAP_HTTPS` after deprecating Node <9.
548
- if (SHOULD_WRAP_HTTPS || !IS_HTTPS) {
539
+ if (SHOULD_WRAP_HTTPS || !IS_HTTPS) {
549
540
  shimmer.wrapMethod(
550
541
  http,
551
542
  'http',
@@ -553,21 +544,12 @@ module.exports = function initialize(agent, http, moduleName) {
553
544
  wrapRequest.bind(null, agent)
554
545
  )
555
546
 
556
- // Upon updating to https-proxy-agent v2, we are now using
557
- // agent-base v4, which patches https.get to use https.request.
558
- //
559
- // https://github.com/TooTallNate/node-agent-base/commit/7de92df780e147d4618
560
- //
561
- // This means we need to skip instrumenting to avoid double
562
- // instrumenting external requests.
563
- if (!IS_HTTPS && psemver.satisfies('>=8')) {
564
- shimmer.wrapMethod(
565
- http,
566
- 'http',
567
- 'get',
568
- wrapRequest.bind(null, agent)
569
- )
570
- }
547
+ shimmer.wrapMethod(
548
+ http,
549
+ 'http',
550
+ 'get',
551
+ wrapRequest.bind(null, agent)
552
+ )
571
553
  }
572
554
 
573
555
  shimmer.wrapMethod(
@@ -592,58 +574,6 @@ module.exports = function initialize(agent, http, moduleName) {
592
574
  }
593
575
  }
594
576
  )
595
-
596
- // http.Client is deprecated, but still in use
597
- // TODO: Remove this once Node <7 is deprecated.
598
- var DeprecatedClient, deprecatedCreateClient
599
- function clearGetters() {
600
- if (DeprecatedClient) {
601
- delete http.Client
602
- http.Client = DeprecatedClient
603
- }
604
- if (deprecatedCreateClient) {
605
- delete http.createClient
606
- http.createClient = deprecatedCreateClient
607
- }
608
- }
609
-
610
- // TODO: Remove this once Node <7 is deprecated.
611
- DeprecatedClient = shimmer.wrapDeprecated(
612
- http,
613
- 'http',
614
- 'Client',
615
- {
616
- get: function get() {
617
- var example = new DeprecatedClient(80, 'localhost')
618
- wrapLegacyClient(agent, example.constructor.prototype)
619
- clearGetters()
620
-
621
- return DeprecatedClient
622
- },
623
- set: function set(NewClient) {
624
- DeprecatedClient = NewClient
625
- }
626
- }
627
- )
628
-
629
- // TODO: Remove this once Node <7 is deprecated.
630
- deprecatedCreateClient = shimmer.wrapDeprecated(
631
- http,
632
- 'http',
633
- 'createClient',
634
- {
635
- get: function get() {
636
- var example = deprecatedCreateClient(80, 'localhost')
637
- wrapLegacyClient(agent, example.constructor.prototype)
638
- clearGetters()
639
-
640
- return deprecatedCreateClient
641
- },
642
- set: function set(newCreateClient) {
643
- deprecatedCreateClient = newCreateClient
644
- }
645
- }
646
- )
647
577
  }
648
578
 
649
579
  /**
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
- var shared = require('./shared')
3
+ const shared = require('./shared')
4
+ const record = require('../../metrics/recorders/generic')
4
5
 
5
6
  // TODO: abstract and consolidate mostly-shared hapi functionality
6
7
  module.exports = function initialize(agent, hapi, moduleName, shim) {
@@ -154,14 +155,20 @@ function wrapPreHandlers(shim, container, path) {
154
155
  }
155
156
  return container
156
157
  } else if (shim.isFunction(container)) {
157
- return wrapRouteHandler(shim, container, path)
158
+ return wrapPreHandler(shim, container, path)
158
159
  } else if (container.method && shim.isFunction(container.method)) {
159
160
  return shim.wrap(container, 'method', function wrapHandler(shim, handler) {
160
- return wrapRouteHandler(shim, handler, path)
161
+ return wrapPreHandler(shim, handler, path)
161
162
  })
162
163
  }
163
164
  }
164
165
 
166
+ function wrapPreHandler(shim, container, path) {
167
+ return shim.record(container, (shim) => {
168
+ return {name: [shim.HAPI, ' pre handler: ','(',path,')'].join(''), recorder: record}
169
+ })
170
+ }
171
+
165
172
  function wrapRouteHandler(shim, handler, path) {
166
173
  return shim.recordMiddleware(handler, {
167
174
  route: path,
@@ -11,6 +11,7 @@ const SUPPORTABILITY = {
11
11
  UNINSTRUMENTED: 'Supportability/Uninstrumented',
12
12
  EVENTS: 'Supportability/Events',
13
13
  API: 'Supportability/API',
14
+ TRANSACTION_API: 'Supportability/API/Transaction',
14
15
  UTILIZATION: 'Supportability/utilization',
15
16
  DEPENDENCIES: 'Supportability/InstalledDependencies',
16
17
  NODEJS: 'Supportability/Nodejs',
@@ -2,22 +2,23 @@
2
2
 
3
3
  const apiGateway = require('./api-gateway')
4
4
  const headerAttributes = require('../header-attributes')
5
+ const get = require('../util/get')
5
6
  const logger = require('../logger').child({component: 'aws-lambda'})
6
7
  const recordBackground = require('../metrics/recorders/other')
7
8
  const recordWeb = require('../metrics/recorders/http')
8
9
  const TransactionShim = require('../shim/transaction-shim')
9
10
  const urltils = require('../util/urltils')
10
- const TRACE_CONTEXT_PARENT_HEADER
11
- = require('../transaction/tracecontext').TRACE_CONTEXT_PARENT_HEADER
12
- const TRACE_CONTEXT_STATE_HEADER
13
- = require('../transaction/tracecontext').TRACE_CONTEXT_STATE_HEADER
14
11
 
15
12
  // CONSTANTS
16
13
  const ATTR_DEST = require('../config/attribute-filter').DESTINATIONS
17
14
  const COLD_START_KEY = 'aws.lambda.coldStart'
18
- const EVENT_SOURCE_ARN_KEY = 'aws.lambda.eventSource.arn'
15
+ const EVENT_SOURCE_PREFIX = 'aws.lambda.eventSource'
16
+ const EVENT_SOURCE_ARN_KEY = `${EVENT_SOURCE_PREFIX}.arn`
17
+ const EVENT_SOURCE_TYPE_KEY = `${EVENT_SOURCE_PREFIX}.eventType`
19
18
  const NAMES = require('../metrics/names')
20
19
 
20
+ const EVENT_SOURCE_INFO = require('./event-sources')
21
+
21
22
  // A function with no references used to stub out closures
22
23
  function cleanClosure() {}
23
24
 
@@ -38,13 +39,27 @@ class AwsLambda {
38
39
  this.shim = new TransactionShim(agent, 'aws-lambda')
39
40
  }
40
41
 
41
- // FOR TESTING PURPORSES ONLY
42
+ // FOR TESTING PURPOSES ONLY
42
43
  _resetModuleState() {
43
44
  patchCalled = false
44
45
  coldStartRecorded = false
45
46
  transactionEnders = []
46
47
  }
47
48
 
49
+ _detectEventType(event) {
50
+ const pathMatch = (obj, path) => {
51
+ return get(obj, path, null) !== null
52
+ }
53
+
54
+ for (const typeInfo of Object.values(EVENT_SOURCE_INFO)) {
55
+ if (typeInfo.required_keys.every((path) => pathMatch(event, path))) {
56
+ return typeInfo
57
+ }
58
+ }
59
+
60
+ return null
61
+ }
62
+
48
63
  patchLambdaHandler(handler) {
49
64
  const awsLambda = this
50
65
  const shim = this.shim
@@ -161,13 +176,34 @@ class AwsLambda {
161
176
 
162
177
  segment.start()
163
178
 
164
- let res = shim.applySegment(handler, segment, false, this, args)
179
+ let res
180
+ try {
181
+ res = shim.applySegment(handler, segment, false, this, args)
182
+ } catch (err) {
183
+ uncaughtException = err
184
+ txnEnder()
185
+ throw err
186
+ }
165
187
  if (shim.isPromise(res)) {
166
- res = shim.interceptPromise(res, txnEnder)
188
+ res = lambdaInterceptPromise(res, txnEnder)
167
189
  }
168
190
  return res
169
191
  }
170
192
 
193
+ // In order to capture error events
194
+ // we need to store the error in uncaughtException
195
+ // otherwise the transaction will end before they are captured
196
+ function lambdaInterceptPromise(prom, cb) {
197
+ return prom.then(function onThen(arg) {
198
+ cb()
199
+ return arg
200
+ }, function onCatch(err) {
201
+ uncaughtException = err
202
+ cb()
203
+ throw err // This is not our error, just rethrowing the promise rejection.
204
+ })
205
+ }
206
+
171
207
  function wrapCallbackAndCaptureError(transaction, txnEnder, cb, processResult) {
172
208
  return function wrappedCallback() {
173
209
  let err = arguments[0]
@@ -195,6 +231,22 @@ class AwsLambda {
195
231
  'aws.requestId': context.awsRequestId
196
232
  }
197
233
 
234
+ const eventSourceInfo = this._detectEventType(event)
235
+
236
+ if (eventSourceInfo) {
237
+ attributes[EVENT_SOURCE_TYPE_KEY] = eventSourceInfo.name
238
+
239
+ for (const key of Object.keys(eventSourceInfo.attributes)) {
240
+ const value = get(event, eventSourceInfo.attributes[key], null)
241
+
242
+ if (value === null) {
243
+ continue
244
+ }
245
+
246
+ attributes[key] = value
247
+ }
248
+ }
249
+
198
250
  setEventSourceAttributes(event, attributes)
199
251
 
200
252
  if (!coldStartRecorded) {
@@ -223,6 +275,11 @@ function setEventSourceAttributes(event, attributes) {
223
275
  } else if (event.records && event.deliveryStreamArn) {
224
276
  // Kinesis Firehose
225
277
  attributes[EVENT_SOURCE_ARN_KEY] = event.deliveryStreamArn
278
+ } else if (event.requestContext && event.requestContext.elb &&
279
+ event.requestContext.elb.targetGroupArn) {
280
+ attributes[EVENT_SOURCE_ARN_KEY] = event.requestContext.elb.targetGroupArn
281
+ } else if (event.resources && event.resources[0]) {
282
+ attributes[EVENT_SOURCE_ARN_KEY] = event.resources[0]
226
283
  } else {
227
284
  logger.trace('Unable to determine ARN for event type.', event)
228
285
  }
@@ -263,34 +320,23 @@ function setWebRequest(shim, transaction, request) {
263
320
  headerAttributes.collectRequestHeaders(request.headers, transaction)
264
321
 
265
322
  if (shim.agent.config.distributed_tracing.enabled) {
266
- // W3C Fork based on format
267
- if (shim.agent.config.feature_flag.dt_format_w3c) {
268
- const traceparent = request.headers[TRACE_CONTEXT_PARENT_HEADER]
269
- const tracestate = request.headers[TRACE_CONTEXT_STATE_HEADER]
270
- if (traceparent && tracestate) {
271
- logger.trace(
272
- 'Accepting trace context payload for transaction %s',
273
- transaction.id
274
- )
275
- transaction.acceptTraceContextPayload(traceparent, tracestate)
276
- }
277
- } else {
278
- // These are the three cases specified in the DT spec
279
- // https://source.datanerd.us/agents/agent-specs/blob/master/Distributed-Tracing.md#supported-transports
280
- const payload = request.headers.newrelic || request.headers.NEWRELIC ||
281
- request.headers.Newrelic
282
-
283
- if (payload) {
284
- logger.trace(
285
- 'Accepting distributed trace payload for transaction %s',
286
- transaction.id
287
- )
288
- transaction.acceptDistributedTracePayload(payload, request.transportType)
289
- }
290
- }
323
+ const lowercaseHeaders = lowercaseObjectKeys(request.headers)
324
+
325
+ const transportType = request.transportType && request.transportType.toUpperCase()
326
+ transaction.acceptDistributedTraceHeaders(transportType, lowercaseHeaders)
291
327
  }
292
328
  }
293
329
 
330
+ function lowercaseObjectKeys(original) {
331
+ const lowercaseObject = Object.keys(original)
332
+ .reduce((destination, key) => {
333
+ destination[key.toLowerCase()] = original[key]
334
+ return destination
335
+ }, {})
336
+
337
+ return lowercaseObject
338
+ }
339
+
294
340
  function endTransaction(transaction, enderIndex) {
295
341
  if (transactionEnders[enderIndex] === cleanClosure) {
296
342
  // In the case where we have already been called, we return early. There may be a