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.
- package/NEWS.md +33 -0
- package/bin/create-github-release.js +109 -0
- package/bin/create-release-tag.js +95 -0
- package/bin/git-commands.js +110 -0
- package/bin/github.js +29 -4
- package/bin/npm-commands.js +31 -0
- package/bin/prepare-release.js +359 -0
- package/bin/run-versioned-tests.sh +1 -9
- package/index.js +4 -2
- package/lib/agent.js +4 -0
- package/lib/collector/api.js +45 -18
- package/lib/collector/remote-method.js +14 -5
- package/lib/config/index.js +21 -4
- package/lib/instrumentation/core/timers.js +6 -1
- package/lib/metrics/names.js +7 -1
- package/lib/transaction/index.js +7 -0
- package/package.json +3 -4
- package/bin/create-release.js +0 -74
- package/bin/generate-release-notes.js +0 -126
- package/bin/travis-install-gcc5.sh +0 -13
- package/bin/travis-install-mongo.sh +0 -16
- package/bin/travis-node.sh +0 -57
- package/bin/travis-setup.sh +0 -52
- package/bin/update-changelog-version.js +0 -68
|
@@ -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
|
-
|
|
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
|
|
80
|
-
logger.info('
|
|
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
|
/**
|
package/lib/collector/api.js
CHANGED
|
@@ -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
|
-
|
|
62
|
-
|
|
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.
|
|
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
|
-
|
|
192
|
-
|
|
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.
|
|
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
|
-
|
|
245
|
-
|
|
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.
|
|
92
|
-
host: this.
|
|
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.
|
|
329
|
+
'Host': this.endpoint.host,
|
|
321
330
|
'User-Agent': agent,
|
|
322
331
|
'Connection': 'Keep-Alive',
|
|
323
332
|
'Content-Length': byteLength(options.body),
|
package/lib/config/index.js
CHANGED
|
@@ -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
|
|
1684
|
+
locations += ' or ' + altpath
|
|
1671
1685
|
}
|
|
1672
1686
|
|
|
1673
|
-
|
|
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('
|
|
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
|
|
64
|
+
const segment = shim.getActiveSegment()
|
|
65
|
+
if (!segment) {
|
|
66
|
+
return fn.apply(this, arguments)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const args = shim.argsToArray.apply(shim, arguments, segment)
|
|
65
70
|
shim.bindSegment(args, shim.FIRST)
|
|
66
71
|
|
|
67
72
|
return fn.apply(this, args)
|
package/lib/metrics/names.js
CHANGED
|
@@ -22,7 +22,8 @@ const SUPPORTABILITY = {
|
|
|
22
22
|
NODEJS: 'Supportability/Nodejs',
|
|
23
23
|
REGISTRATION: 'Supportability/Registration',
|
|
24
24
|
EVENT_HARVEST: 'Supportability/EventHarvest',
|
|
25
|
-
INFINITE_TRACING: 'Supportability/InfiniteTracing'
|
|
25
|
+
INFINITE_TRACING: 'Supportability/InfiniteTracing',
|
|
26
|
+
FEATURES: 'Supportability/Features'
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
const ERRORS = {
|
|
@@ -249,6 +250,10 @@ const INFINITE_TRACING = {
|
|
|
249
250
|
DRAIN_DURATION: SUPPORTABILITY.INFINITE_TRACING + '/Drain/Duration',
|
|
250
251
|
}
|
|
251
252
|
|
|
253
|
+
const FEATURES = {
|
|
254
|
+
CERTIFICATES: SUPPORTABILITY.FEATURES + '/Certificates'
|
|
255
|
+
}
|
|
256
|
+
|
|
252
257
|
module.exports = {
|
|
253
258
|
ACTION_DELIMITER: '/',
|
|
254
259
|
ALL: ALL,
|
|
@@ -266,6 +271,7 @@ module.exports = {
|
|
|
266
271
|
EVENT_HARVEST: EVENT_HARVEST,
|
|
267
272
|
EXPRESS: EXPRESS,
|
|
268
273
|
EXTERNAL: EXTERNAL,
|
|
274
|
+
FEATURES,
|
|
269
275
|
FS: FS,
|
|
270
276
|
FUNCTION: FUNCTION,
|
|
271
277
|
GC: GC,
|
package/lib/transaction/index.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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",
|