newrelic 7.1.2 → 7.1.3

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.
@@ -0,0 +1,359 @@
1
+ 'use strict'
2
+
3
+ const fs = require('fs')
4
+
5
+ const {program, Option} = require('commander')
6
+
7
+ const Github = require('./github')
8
+ const git = require('./git-commands')
9
+ const npm = require('./npm-commands')
10
+
11
+ const FILE_NAME = 'NEWS.md'
12
+ const PROPOSED_NOTES_HEADER = 'Proposed Release Notes'
13
+
14
+ const FORCE_RUN_DEAFULT_REMOTE = 'origin'
15
+
16
+ // Add command line options
17
+ program.addOption(
18
+ new Option('--release-type <releaseType>', 'release type')
19
+ .choices(['patch', 'minor', 'major'])
20
+ .makeOptionMandatory()
21
+ )
22
+ program.option('--major-release', 'create a major release. (release-type option must be set to \'major\')')
23
+ program.option('--remote <remote>', 'remote to push branch to', 'origin')
24
+ program.option('--branch <branch>', 'branch to generate notes from', 'main')
25
+ program.option('--repo-owner <repoOwner>', 'repository owner', 'newrelic')
26
+ program.option('--dry-run', 'generate notes without creating a branch or PR')
27
+ program.option('--no-pr', 'generate notes and branch but do not create PR')
28
+ program.option('-f --force', 'bypass validation')
29
+
30
+ function stopOnError(err) {
31
+ if (err) {
32
+ console.error(err)
33
+ }
34
+
35
+ console.log('Halting execution with exit code: 1')
36
+ process.exit(1)
37
+ }
38
+
39
+ function logStep(step) {
40
+ console.log(`\n ----- [Step]: ${step} -----\n`)
41
+ }
42
+
43
+ async function prepareReleaseNotes() {
44
+ // Parse commandline options inputs
45
+ program.parse()
46
+
47
+ const options = program.opts()
48
+
49
+ console.log('Script running with following options: ', JSON.stringify(options))
50
+
51
+ logStep('Validation')
52
+
53
+ if (options.force) {
54
+ console.log('--force set. Skipping validation logic')
55
+ }
56
+
57
+ const startingBranch = options.branch.replace('refs/heads/', '')
58
+
59
+ const isValid = options.force || (
60
+ await validateReleaseType(options.releaseType, options.majorRelease) &&
61
+ await validateRemote(options.remote) &&
62
+ await validateLocalChanges() &&
63
+ await validateCurrentBranch(startingBranch)
64
+ )
65
+
66
+ if (!isValid) {
67
+ console.log('Invalid configuration. Halting script.')
68
+ stopOnError()
69
+ }
70
+
71
+ const remote = options.remote || FORCE_RUN_DEAFULT_REMOTE
72
+ console.log('Using remote: ', remote)
73
+
74
+ try {
75
+ logStep('Increment Version')
76
+
77
+ await npm.version(options.releaseType, false)
78
+
79
+ const packagePath = '../package.json'
80
+ console.log('Extracting new version from package.json here: ', )
81
+ const packageInfo = require(packagePath)
82
+
83
+ const version = `v${packageInfo.version}`
84
+ console.log('New version is: ', version)
85
+
86
+ logStep('Branch Creation')
87
+
88
+ const newBranchName = `release/${version}`
89
+
90
+ if (options.dryRun) {
91
+ console.log('Dry run indicated (--dry-run), not creating branch.')
92
+ } else {
93
+ console.log('Creating and checking out new branch: ', newBranchName)
94
+ await git.checkoutNewBranch(newBranchName)
95
+ }
96
+
97
+ logStep('Commit Package Files')
98
+
99
+ if (options.dryRun) {
100
+ console.log('Dry run indicated (--dry-run), not committing package files.')
101
+ } else {
102
+ console.log('Adding and committing package files.')
103
+ await git.addAllFiles()
104
+ await git.commit(`Setting version to ${version}.`)
105
+ }
106
+
107
+ logStep('Create Release Notes')
108
+
109
+ const releaseData = await generateReleaseNotes()
110
+ await updateReleaseNotesFile(FILE_NAME, version, releaseData.notes)
111
+
112
+ if (options.dryRun) {
113
+ console.log('\nDry run indicated (--dry-run), skipping remaining steps.')
114
+ return
115
+ }
116
+
117
+ logStep('Commit Release Notes')
118
+
119
+ console.log('Adding and committing release notes.')
120
+ await git.addAllFiles()
121
+ await git.commit('Adds auto-generated release notes.')
122
+
123
+ logStep('Push Branch')
124
+
125
+ console.log('Pushing branch to remote: ', remote)
126
+ await git.pushToRemote(remote, newBranchName)
127
+
128
+ logStep('Create Pull Request')
129
+ if (!options.pr) {
130
+ console.log('No PR creation indicated (--no-pr), skipping remaining steps.')
131
+ return
132
+ }
133
+
134
+ if (!process.env.GITHUB_TOKEN) {
135
+ console.log('GITHUB_TOKEN required to create a pull request (PR)')
136
+ stopOnError()
137
+ }
138
+
139
+ console.log('Creating draft PR with new release notes for repo owner: ', options.repoOwner)
140
+ const remoteApi = new Github(options.repoOwner)
141
+ const title = 'Updates release notes for next release'
142
+ const body = getFormattedPrBody(releaseData)
143
+ const prOptions = {
144
+ head: newBranchName,
145
+ base: 'main',
146
+ title,
147
+ body,
148
+ draft: true
149
+ }
150
+
151
+ await remoteApi.createPR(prOptions)
152
+
153
+ console.log('*** Full Run Successful ***')
154
+ } catch (err) {
155
+ stopOnError(err)
156
+ }
157
+ }
158
+
159
+ async function validateReleaseType(releaseType, majorFlag) {
160
+ if (releaseType === 'major' && !majorFlag) {
161
+ console.log('WARNING: you must set the \'-m\' flag to create a major release.')
162
+ return false
163
+ }
164
+
165
+ if (majorFlag && releaseType !== 'major') {
166
+ console.log(`WARNING: ignoring \'-m, --major-release\' option as release type set to ${options.rel}.`)
167
+ return false
168
+ }
169
+
170
+ return true
171
+ }
172
+
173
+ async function validateRemote(remote) {
174
+ try {
175
+ const remotes = await git.getPushRemotes()
176
+
177
+ if (!remote) {
178
+ console.log('No remote configured. Please execute with --remote.')
179
+ console.log('Available remotes are: ', remotes)
180
+ return false
181
+ }
182
+
183
+ if (!remotes[remote]) {
184
+ console.log(`Configured remote (${remote}) not found in ${JSON.stringify(remotes)}`)
185
+ return false
186
+ }
187
+
188
+ return true
189
+ } catch (err) {
190
+ console.error(err)
191
+ return false
192
+ }
193
+ }
194
+
195
+ async function validateLocalChanges() {
196
+ try {
197
+ const localChanges = await git.getLocalChanges()
198
+ if (localChanges.length > 0) {
199
+ console.log('Local changes detected: ', localChanges)
200
+ console.log('Please commit to a feature branch or stash changes and then try again.')
201
+ return false
202
+ }
203
+
204
+ return true
205
+ } catch (err) {
206
+ console.error(err)
207
+ return false
208
+ }
209
+ }
210
+
211
+ async function validateCurrentBranch(branch) {
212
+ try {
213
+ const currentBranch = await git.getCurrentBranch()
214
+
215
+ if (branch != currentBranch) {
216
+ console.log(
217
+ 'Current checked-out branch (%s) does not match expected (%s)',
218
+ currentBranch,
219
+ branch
220
+ )
221
+ return false
222
+ }
223
+
224
+ return true
225
+ } catch (err) {
226
+ console.error(err)
227
+ return false
228
+ }
229
+ }
230
+
231
+ async function generateReleaseNotes() {
232
+ const github = new Github()
233
+ const latestRelease = await github.getLatestRelease()
234
+ console.log(`The latest release is: ${latestRelease.name} published: ${latestRelease.published_at}`)
235
+ console.log(`Tag: ${latestRelease.tag_name}, Target: ${latestRelease.target_commitish}`)
236
+
237
+ const tag = await github.getTagByName(latestRelease.tag_name)
238
+ console.log('The tag commit sha is: ', tag.commit.sha)
239
+
240
+ const commit = await github.getCommit(tag.commit.sha)
241
+ const commitDate = commit.commit.committer.date
242
+
243
+ console.log(`Finding merged pull requests since: ${commitDate}`)
244
+
245
+ const mergedPullRequests = await github.getMergedPullRequestsSince(commitDate)
246
+ console.log(`Found ${mergedPullRequests.length}`)
247
+
248
+ const releaseNoteData = mergedPullRequests.map((pr) => {
249
+ const parts = pr.body.split(/(?:^|\n)##\s*/g)
250
+
251
+ // If only has one part, not in appropriate format.
252
+ if (parts.length === 1) {
253
+ return {
254
+ notes: generateUnformattedNotes(pr.body),
255
+ url: pr.html_url
256
+ }
257
+ }
258
+
259
+ const {1: proposedReleaseNotes} = parts
260
+
261
+ const titleRemoved = proposedReleaseNotes.replace(PROPOSED_NOTES_HEADER, '')
262
+ return {
263
+ notes: titleRemoved,
264
+ url: pr.html_url
265
+ }
266
+ })
267
+
268
+ const finalData = releaseNoteData.reduce((result, currentValue) => {
269
+ const trimmedNotes = currentValue.notes.trim()
270
+ if (trimmedNotes) { // avoid adding lines for empty notes
271
+ result.notes += '\n\n' + trimmedNotes
272
+ }
273
+ result.links += `\n* PR: ${currentValue.url}`
274
+ return result
275
+ }, {
276
+ notes: '',
277
+ links: ''
278
+ })
279
+
280
+ return finalData
281
+ }
282
+
283
+ function generateUnformattedNotes(originalNotes) {
284
+ let unformattedNotes = originalNotes
285
+
286
+ // Drop extra snyk details and just keep high-level summary.
287
+ if (originalNotes.indexOf('snyk:metadata') >= 0) {
288
+ const snykParts = originalNotes.split('<hr/>')
289
+ const {0: snykDescription} = snykParts
290
+
291
+ unformattedNotes = snykDescription.trim()
292
+ }
293
+
294
+ const needsReviewNotes = [
295
+ '--- NOTES NEEDS REVIEW ---',
296
+ unformattedNotes,
297
+ '--------------------------'
298
+ ].join('\n')
299
+
300
+ return needsReviewNotes
301
+ }
302
+
303
+ function updateReleaseNotesFile(file, version, newNotes) {
304
+ const promise = new Promise((resolve, reject) => {
305
+ fs.readFile(file, 'utf8', function (err, data) {
306
+ if (err) {
307
+ return reject(err)
308
+ }
309
+
310
+ if (data.startsWith(`### ${version}`)) {
311
+ const errMessage = [
312
+ `${file} already contains '${version}'`,
313
+ `Delete existing ${version} release notes (if desired) and run again`
314
+ ].join('\n')
315
+
316
+ return reject(new Error(errMessage))
317
+ }
318
+
319
+ // toISOString() will always return UTC time
320
+ const todayFormatted = new Date().toISOString().split('T')[0]
321
+ const newVersionHeader = `### ${version} (${todayFormatted})`
322
+
323
+ const newContent = [
324
+ newVersionHeader,
325
+ newNotes,
326
+ '\n\n',
327
+ data
328
+ ].join('')
329
+
330
+ fs.writeFile(file, newContent, 'utf8', function (err) {
331
+ if (err) {
332
+ return reject(err)
333
+ }
334
+
335
+ console.log(`Added new release notes to ${file} under ${newVersionHeader}`)
336
+
337
+ resolve()
338
+ })
339
+ })
340
+ })
341
+
342
+ return promise
343
+ }
344
+
345
+ function getFormattedPrBody(data) {
346
+ const body = [
347
+ '## Proposed Release Notes',
348
+ data.notes,
349
+ '## Links',
350
+ data.links,
351
+ '',
352
+ '## Details',
353
+ ''
354
+ ].join('\n')
355
+
356
+ return body
357
+ }
358
+
359
+ prepareReleaseNotes()
@@ -9,9 +9,6 @@ VERSIONED_MODE="${VERSIONED_MODE:---major}"
9
9
  if [[ $TRAVIS_BRANCH == `git describe --tags --always HEAD` ]]; then
10
10
  VERSIONED_MODE=--minor
11
11
  fi
12
- # if [[ $TRAVIS_BRANCH == "master" ]]; then
13
- # VERSIONED_MODE=--minor
14
- # fi
15
12
 
16
13
  set -f
17
14
  directories=()
@@ -24,9 +21,4 @@ fi
24
21
 
25
22
  export AGENT_PATH=`pwd`
26
23
 
27
- # Don't run the aws-sdk tests if we don't have the keys set
28
- if [[ -z "$AWS_ACCESS_KEY_ID" ]]; then
29
- time ./node_modules/.bin/versioned-tests $VERSIONED_MODE -i 2 -s aws-sdk ${directories[@]}
30
- else
31
- time ./node_modules/.bin/versioned-tests $VERSIONED_MODE -i 2 ${directories[@]}
32
- fi
24
+ time ./node_modules/.bin/versioned-tests $VERSIONED_MODE -i 2 ${directories[@]}
package/index.js CHANGED
@@ -76,8 +76,10 @@ function initialize() {
76
76
  // just pipes to stdout.
77
77
  logger = require('./lib/logger')
78
78
 
79
- if (!config || !config.agent_enabled) {
80
- logger.info('Module not enabled in configuration; not starting.')
79
+ if (!config) {
80
+ logger.info('No configuration detected. Not starting.')
81
+ } else if (!config.agent_enabled) {
82
+ logger.info('Module disabled in configuration. Not starting.')
81
83
  } else {
82
84
  agent = createAgent(config)
83
85
  addStartupSupportabilities(agent)
package/lib/agent.js CHANGED
@@ -458,6 +458,10 @@ Agent.prototype.onConnect = function onConnect() {
458
458
  this.spanEventAggregator.reconfigure(this.config)
459
459
  this.transactionEventAggregator.reconfigure(this.config)
460
460
  this.customEventAggregator.reconfigure(this.config)
461
+
462
+ if (this.config.certificates && this.config.certificates.length > 0) {
463
+ this.metrics.getOrCreateMetric(NAMES.FEATURES.CERTIFICATES).incrementCallCount()
464
+ }
461
465
  }
462
466
 
463
467
  /**
@@ -12,6 +12,8 @@ const RemoteMethod = require('./remote-method')
12
12
 
13
13
  const NAMES = require('../metrics/names')
14
14
 
15
+ const DEFAULT_PORT = 443
16
+
15
17
  // just to make clear what's going on
16
18
  const TO_MILLIS = 1e3
17
19
 
@@ -54,22 +56,41 @@ function CollectorAPI(agent) {
54
56
  this._agent = agent
55
57
  this._reqHeadersMap = null
56
58
 
59
+ const initialEndpoint = {
60
+ host: agent.config.host,
61
+ port: agent.config.port
62
+ }
63
+
57
64
  /* RemoteMethods can be reused and have little per-object state, so why not
58
65
  * save some GC time?
59
66
  */
60
67
  this._methods = {
61
- redirect: new RemoteMethod('preconnect', agent.config),
62
- handshake: new RemoteMethod('connect', agent.config),
63
- settings: new RemoteMethod('agent_settings', agent.config),
64
- errors: new RemoteMethod('error_data', agent.config),
65
- metrics: new RemoteMethod('metric_data', agent.config),
66
- traces: new RemoteMethod('transaction_sample_data', agent.config),
67
- shutdown: new RemoteMethod('shutdown', agent.config),
68
- events: new RemoteMethod('analytic_event_data', agent.config),
69
- customEvents: new RemoteMethod('custom_event_data', agent.config),
70
- queryData: new RemoteMethod('sql_trace_data', agent.config),
71
- errorEvents: new RemoteMethod('error_event_data', agent.config),
72
- spanEvents: new RemoteMethod('span_event_data', agent.config)
68
+ preconnect: new RemoteMethod('preconnect', agent.config, initialEndpoint),
69
+ connect: new RemoteMethod('connect', agent.config, initialEndpoint),
70
+ settings: new RemoteMethod('agent_settings', agent.config, initialEndpoint),
71
+ errors: new RemoteMethod('error_data', agent.config, initialEndpoint),
72
+ metrics: new RemoteMethod('metric_data', agent.config, initialEndpoint),
73
+ traces: new RemoteMethod('transaction_sample_data', agent.config, initialEndpoint),
74
+ shutdown: new RemoteMethod('shutdown', agent.config, initialEndpoint),
75
+ events: new RemoteMethod('analytic_event_data', agent.config, initialEndpoint),
76
+ customEvents: new RemoteMethod('custom_event_data', agent.config, initialEndpoint),
77
+ queryData: new RemoteMethod('sql_trace_data', agent.config, initialEndpoint),
78
+ errorEvents: new RemoteMethod('error_event_data', agent.config, initialEndpoint),
79
+ spanEvents: new RemoteMethod('span_event_data', agent.config, initialEndpoint)
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Updates all methods except preconnect w/ new host/port pairs sent down from server
85
+ * during preconnect (via redirect_host). Preconnect does not update.
86
+ */
87
+ CollectorAPI.prototype._updateEndpoints = function _updateEndpoints(endpoint) {
88
+ logger.trace('Updating endpoints to: ', endpoint)
89
+ for (const [key, remoteMethod] of Object.entries(this._methods)) {
90
+ // Preconnect should always use configured options, not updates from server.
91
+ if (key !== 'preconnect') {
92
+ remoteMethod.updateEndpoint(endpoint)
93
+ }
73
94
  }
74
95
  }
75
96
 
@@ -160,7 +181,7 @@ CollectorAPI.prototype._login = function _login(callback) {
160
181
 
161
182
  const payload = [preconnectData]
162
183
 
163
- methods.redirect.invoke(payload, onPreConnect)
184
+ methods.preconnect.invoke(payload, onPreConnect)
164
185
 
165
186
  function onPreConnect(error, response) {
166
187
  if (error || !SUCCESS.has(response.status)) {
@@ -188,8 +209,13 @@ CollectorAPI.prototype._login = function _login(callback) {
188
209
  res.redirect_host
189
210
  )
190
211
 
191
- agent.config.host = parts[0]
192
- agent.config.port = parts[1] || 443
212
+ const [host, port] = parts
213
+ const newEndpoint = {
214
+ host: host,
215
+ port: port || DEFAULT_PORT
216
+ }
217
+
218
+ self._updateEndpoints(newEndpoint)
193
219
  }
194
220
  }
195
221
 
@@ -226,7 +252,7 @@ CollectorAPI.prototype._connect = function _connect(env, callback) {
226
252
  const methods = this._methods
227
253
  const agent = this._agent
228
254
 
229
- methods.handshake.invoke(env, onConnect)
255
+ methods.connect.invoke(env, onConnect)
230
256
 
231
257
  function onConnect(error, res) {
232
258
  if (error || !SUCCESS.has(res.status)) {
@@ -239,10 +265,11 @@ CollectorAPI.prototype._connect = function _connect(env, callback) {
239
265
  }
240
266
 
241
267
  agent.setState('connected')
268
+
242
269
  logger.info(
243
270
  'Connected to %s:%d with agent run ID %s.',
244
- agent.config.host,
245
- agent.config.port,
271
+ methods.connect.endpoint.host,
272
+ methods.connect.endpoint.port,
246
273
  config.agent_run_id
247
274
  )
248
275
 
@@ -29,15 +29,24 @@ const USER_AGENT_FORMAT = 'NewRelic-NodeAgent/%s (nodejs %s %s-%s)'
29
29
  const ENCODING_HEADER = 'CONTENT-ENCODING'
30
30
  const DEFAULT_ENCODING = 'identity'
31
31
 
32
- function RemoteMethod(name, config) {
32
+ function RemoteMethod(name, config, endpoint) {
33
33
  if (!name) {
34
34
  throw new TypeError('Must include name of method to invoke on collector.')
35
35
  }
36
36
 
37
37
  this.name = name
38
38
  this._config = config
39
-
40
39
  this._protocolVersion = 17
40
+
41
+ this.endpoint = endpoint
42
+ }
43
+
44
+ RemoteMethod.prototype.updateEndpoint = function updateEndpoint(endpoint) {
45
+ if (!endpoint) {
46
+ return
47
+ }
48
+
49
+ this.endpoint = endpoint
41
50
  }
42
51
 
43
52
  RemoteMethod.prototype.serialize = function serialize(payload, callback) {
@@ -88,8 +97,8 @@ RemoteMethod.prototype.invoke = function invoke(payload, nrHeaders, callback) {
88
97
  RemoteMethod.prototype._post = function _post(data, nrHeaders, callback) {
89
98
  var method = this
90
99
  var options = {
91
- port: this._config.port,
92
- host: this._config.host,
100
+ port: this.endpoint.port,
101
+ host: this.endpoint.host,
93
102
  compressed: this._shouldCompress(data),
94
103
  path: this._path(),
95
104
  onError: callback,
@@ -317,7 +326,7 @@ RemoteMethod.prototype._headers = function _headers(options) {
317
326
 
318
327
  var headers = {
319
328
  // select the virtual host on the server end
320
- 'Host': this._config.host,
329
+ 'Host': this.endpoint.host,
321
330
  'User-Agent': agent,
322
331
  'Connection': 'Keep-Alive',
323
332
  'Content-Length': byteLength(options.body),
@@ -1188,6 +1188,20 @@ Config.prototype._DTManuallySet = function _DTManuallySet(inputConfig) {
1188
1188
  */
1189
1189
  Config.prototype._enforceServerless = function _enforceServerless(inputConfig) {
1190
1190
  if (this.serverless_mode.enabled) {
1191
+ // Application name is not currently leveraged by our Lambda product (March 2021).
1192
+ // Defaulting the name removes burden on customers to set while avoiding
1193
+ // breaking should it be used in the future.
1194
+ if (!this.app_name || this.app_name.length === 0) {
1195
+ const namingSource = process.env.AWS_LAMBDA_FUNCTION_NAME
1196
+ ? 'process.env.AWS_LAMBDA_FUNCTION_NAME'
1197
+ : 'DEFAULT'
1198
+
1199
+ const name = process.env.AWS_LAMBDA_FUNCTION_NAME || 'Serverless Application'
1200
+ this.app_name = [name]
1201
+
1202
+ logger.info('Auto-naming serverless application to [\'%s\'] from: %s', name, namingSource)
1203
+ }
1204
+
1191
1205
  // Explicitly disable old CAT in serverless_mode
1192
1206
  if (this.cross_application_tracer.enabled) {
1193
1207
  this.cross_application_tracer.enabled = false
@@ -1667,17 +1681,20 @@ function _noConfigFile() {
1667
1681
 
1668
1682
  let locations = mainpath
1669
1683
  if (mainpath !== altpath) {
1670
- locations += ' or\n' + altpath
1684
+ locations += ' or ' + altpath
1671
1685
  }
1672
1686
 
1673
- /* eslint-disable no-console */
1674
- console.error([
1687
+ const errorMessage = [
1675
1688
  'Unable to find New Relic module configuration. A base configuration file',
1676
1689
  `can be copied from ${BASE_CONFIG_PATH}`,
1677
1690
  `and put at ${locations}.`,
1678
1691
  'If you are not using file-based configuration, please set the environment',
1679
1692
  'variable `NEW_RELIC_NO_CONFIG_FILE=true`.'
1680
- ].join('\n'))
1693
+ ].join(' ')
1694
+
1695
+ logger.error(errorMessage)
1696
+ /* eslint-disable no-console */
1697
+ console.error(errorMessage)
1681
1698
  /* eslint-enable no-console */
1682
1699
  }
1683
1700
 
@@ -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 args = shim.argsToArray.apply(shim, arguments)
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)
@@ -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,
@@ -879,6 +879,13 @@ Transaction.prototype.getIntrinsicAttributes = function getIntrinsicAttributes()
879
879
  */
880
880
  Transaction.prototype.acceptDistributedTraceHeaders = acceptDistributedTraceHeaders
881
881
  function acceptDistributedTraceHeaders(transportType, headers) {
882
+ if (headers == null || typeof headers !== 'object') {
883
+ logger.trace(
884
+ 'Ignoring distributed trace headers for transaction %s. Headers not passed in as object.',
885
+ this.id)
886
+ return
887
+ }
888
+
882
889
  const transport = TRANSPORT_TYPES_SET[transportType] ? transportType : TRANSPORT_TYPES.UNKNOWN
883
890
 
884
891
  // assumes header keys already lowercase
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "7.1.2",
3
+ "version": "7.1.3",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [
@@ -137,14 +137,13 @@
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.5",
146
+ "@grpc/grpc-js": "^1.2.7",
148
147
  "@grpc/proto-loader": "^0.5.5",
149
148
  "@newrelic/aws-sdk": "^3.1.0",
150
149
  "@newrelic/koa": "^5.0.0",