newrelic 7.1.2 → 7.3.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 (52) hide show
  1. package/NEWS.md +97 -0
  2. package/THIRD_PARTY_NOTICES.md +33 -2
  3. package/bin/test-naming-rules.js +4 -4
  4. package/index.js +4 -2
  5. package/lib/agent.js +4 -0
  6. package/lib/collector/api.js +45 -18
  7. package/lib/collector/facts.js +22 -8
  8. package/lib/collector/http-agents.js +20 -7
  9. package/lib/collector/remote-method.js +32 -9
  10. package/lib/config/index.js +48 -39
  11. package/lib/feature_flags.js +6 -2
  12. package/lib/grpc/connection.js +39 -15
  13. package/lib/instrumentation/core/async_hooks.js +101 -14
  14. package/lib/instrumentation/core/http.js +5 -0
  15. package/lib/instrumentation/core/timers.js +6 -1
  16. package/lib/metrics/names.js +7 -1
  17. package/lib/shim/shim.js +6 -1
  18. package/lib/spans/create-span-event-aggregator.js +1 -0
  19. package/lib/spans/span-event.js +6 -3
  20. package/lib/spans/streaming-span-event.js +6 -3
  21. package/lib/transaction/index.js +36 -0
  22. package/newrelic.js +1 -1
  23. package/package.json +19 -7
  24. package/CONTRIBUTING.md +0 -135
  25. package/Migration Guide.md +0 -271
  26. package/ROADMAP_Node.md +0 -24
  27. package/SECURITY.md +0 -5
  28. package/THIRD_PARTY_NOTICES_ADDENDUM.md +0 -213
  29. package/bin/ca-gen.js +0 -91
  30. package/bin/cassandra-setup.sh +0 -11
  31. package/bin/check-workflow-run.js +0 -74
  32. package/bin/clean.sh +0 -18
  33. package/bin/compare-bench-results.js +0 -172
  34. package/bin/create-release.js +0 -74
  35. package/bin/docker-env-vars.sh +0 -15
  36. package/bin/docker-services.sh +0 -49
  37. package/bin/generate-release-notes.js +0 -126
  38. package/bin/github.js +0 -119
  39. package/bin/publish-docs.sh +0 -16
  40. package/bin/run-bench.js +0 -137
  41. package/bin/run-versioned-tests.sh +0 -32
  42. package/bin/smoke.sh +0 -8
  43. package/bin/ssl.sh +0 -87
  44. package/bin/travis-install-gcc5.sh +0 -13
  45. package/bin/travis-install-mongo.sh +0 -16
  46. package/bin/travis-node.sh +0 -57
  47. package/bin/travis-setup.sh +0 -52
  48. package/bin/update-ca-bundle.sh +0 -20
  49. package/bin/update-cats.sh +0 -8
  50. package/bin/update-changelog-version.js +0 -68
  51. package/jsdoc-conf.json +0 -18
  52. package/third_party_manifest.json +0 -619
@@ -14,14 +14,14 @@ const util = require('util')
14
14
 
15
15
  const connectionStates = require('./connection/states')
16
16
 
17
- const protoOptions = {keepCase: true,
17
+ const PROTO_OPTIONS = {keepCase: true,
18
18
  longs: String,
19
19
  enums: String,
20
20
  defaults: true,
21
21
  oneofs: true
22
22
  }
23
23
 
24
- const pathProtoDefinition = __dirname +
24
+ const PROTO_DEFINITION_PATH = __dirname +
25
25
  '../../../lib/grpc/endpoints/infinite-tracing/v1.proto'
26
26
 
27
27
  const DEFAULT_RECONNECT_DELAY_MS = 15 * 1000
@@ -54,11 +54,13 @@ class GrpcConnection extends EventEmitter {
54
54
  this._metrics = metrics
55
55
  this._setState(connectionStates.disconnected)
56
56
 
57
- this._endpoint = this.getTraceObserverEndpoint(traceObserverConfig)
58
57
  this._licensekey = null
59
58
  this._runId = null
60
59
  this._requestHeadersMap = null
61
60
 
61
+ this._endpoint = this.getTraceObserverEndpoint(traceObserverConfig)
62
+
63
+ this._client = null
62
64
  this.stream = null
63
65
  }
64
66
 
@@ -320,26 +322,48 @@ class GrpcConnection extends EventEmitter {
320
322
  * a stream for further writing.
321
323
  */
322
324
  _connectSpans() {
323
- const packageDefinition = protoLoader.loadSync(pathProtoDefinition, protoOptions)
324
-
325
- const serviceDefinition = grpc.loadPackageDefinition(
326
- packageDefinition
327
- ).com.newrelic.trace.v1
328
-
329
- const credentials = this._generateCredentials(grpc)
330
- const client = new serviceDefinition.IngestService(
331
- this._endpoint,
332
- credentials
333
- )
325
+ if (!this._client) {
326
+ // Only create once to avoid potential memory leak.
327
+ // We create here (currently) for consistent error handling.
328
+ this._client = this._createClient(this._endpoint)
329
+ }
334
330
 
335
331
  const metadata =
336
332
  this._getMetadata(this._licenseKey, this._runId, this._requestHeadersMap, process.env)
337
333
 
338
- const stream = client.recordSpan(metadata)
334
+ const stream = this._client.recordSpan(metadata)
339
335
  this._setupSpanStreamObservers(stream)
340
336
 
341
337
  return stream
342
338
  }
339
+
340
+ /**
341
+ * Creates gRPC service client to use for establishing gRPC streams.
342
+ *
343
+ * WARNING: creating a client more than once can result in a memory leak.
344
+ * ChannelImplementation and related objects will stay in memory even after
345
+ * the stream is closed and we do not have a handle to the client. Currently
346
+ * impacting grpc-js@1.2.11 and several earlier versions.
347
+ */
348
+ _createClient(endpoint) {
349
+ logger.trace('Creating gRPC client for: ', endpoint)
350
+
351
+ const packageDefinition = protoLoader.loadSync(PROTO_DEFINITION_PATH, PROTO_OPTIONS)
352
+
353
+ const protoDescriptor = grpc.loadPackageDefinition(
354
+ packageDefinition
355
+ )
356
+
357
+ const traceApi = protoDescriptor.com.newrelic.trace.v1
358
+
359
+ const credentials = this._generateCredentials(grpc)
360
+ const client = new traceApi.IngestService(
361
+ endpoint,
362
+ credentials
363
+ )
364
+
365
+ return client
366
+ }
343
367
  }
344
368
 
345
369
  module.exports = GrpcConnection
@@ -40,7 +40,7 @@ function initialize(agent, shim) {
40
40
  }
41
41
 
42
42
  function tryAsyncHooks(agent, shim) {
43
- var asyncHooks = null
43
+ let asyncHooks = null
44
44
  try {
45
45
  asyncHooks = require('async_hooks')
46
46
  } catch (e) {
@@ -50,19 +50,45 @@ function tryAsyncHooks(agent, shim) {
50
50
 
51
51
  // this map is reused to track the segment that was active when
52
52
  // the before callback is called to be replaced in the after callback
53
- var segmentMap = new Map()
53
+ const segmentMap = new Map()
54
54
  module.exports.segmentMap = segmentMap
55
55
 
56
- var hook = asyncHooks.createHook({
56
+ let hookHandlers = getStandardHooks(segmentMap, agent, shim)
57
+
58
+ if (agent.config.feature_flag.new_promise_tracking) {
59
+ logger.info('Enabling new promise tracking style via new_promise_tracking feature flag.')
60
+ hookHandlers = getPromiseResolveStyleHooks(segmentMap, agent, shim)
61
+ }
62
+
63
+ const hook = asyncHooks.createHook(hookHandlers)
64
+ hook.enable()
65
+
66
+ agent.on('unload', function disableHook() {
67
+ hook.disable()
68
+ })
69
+
70
+ return true
71
+ }
72
+
73
+ function getStandardHooks(segmentMap, agent, shim) {
74
+ const hooks = {
57
75
  init: function initHook(id, type, triggerId, promiseWrap) {
58
- var transaction = agent.getTransaction()
59
- var parentSegment = segmentMap.get(triggerId)
76
+ if (type !== 'PROMISE') {
77
+ return
78
+ }
79
+
80
+ const parentSegment = segmentMap.get(triggerId)
60
81
 
61
- if (!parentSegment && !transaction || type !== 'PROMISE') {
82
+ if (parentSegment && !parentSegment.transaction.isActive()) {
83
+ // Stop propagating if the transaction was ended.
62
84
  return
63
85
  }
64
86
 
65
- var activeSegment = shim.getActiveSegment() || parentSegment
87
+ if (!parentSegment && !agent.getTransaction()) {
88
+ return
89
+ }
90
+
91
+ const activeSegment = shim.getActiveSegment() || parentSegment
66
92
  if (promiseWrap && promiseWrap.promise) {
67
93
  promiseWrap.promise.__NR_id = id
68
94
  }
@@ -70,7 +96,7 @@ function tryAsyncHooks(agent, shim) {
70
96
  },
71
97
 
72
98
  before: function beforeHook(id) {
73
- var hookSegment = segmentMap.get(id)
99
+ const hookSegment = segmentMap.get(id)
74
100
 
75
101
  if (!hookSegment) {
76
102
  return
@@ -80,7 +106,7 @@ function tryAsyncHooks(agent, shim) {
80
106
  shim.setActiveSegment(hookSegment)
81
107
  },
82
108
  after: function afterHook(id) {
83
- var hookSegment = segmentMap.get(id)
109
+ const hookSegment = segmentMap.get(id)
84
110
 
85
111
  // hookSegment is the segment that was active before the promise
86
112
  // executed. If the promise is executing before a segment has been
@@ -96,11 +122,72 @@ function tryAsyncHooks(agent, shim) {
96
122
  destroy: function destHook(id) {
97
123
  segmentMap.delete(id)
98
124
  }
99
- }).enable()
125
+ }
100
126
 
101
- agent.on('unload', function disableHook() {
102
- hook.disable()
103
- })
127
+ return hooks
128
+ }
104
129
 
105
- return true
130
+ function getPromiseResolveStyleHooks(segmentMap, agent, shim) {
131
+ const hooks = {
132
+ init: function initHook(id, type, triggerId, asyncResource) {
133
+ if (type !== 'PROMISE') {
134
+ return
135
+ }
136
+
137
+ let parentSegment = segmentMap.get(triggerId)
138
+
139
+ if (parentSegment && !parentSegment.transaction.isActive()) {
140
+ // Stop propagating if the transaction was ended.
141
+ return
142
+ }
143
+
144
+ if (!parentSegment && !agent.getTransaction()) {
145
+ return
146
+ }
147
+
148
+ const activeSegment = shim.getActiveSegment() || parentSegment
149
+ if (asyncResource && asyncResource.promise) {
150
+ asyncResource.promise.__NR_id = id
151
+ }
152
+
153
+ segmentMap.set(id, activeSegment)
154
+ },
155
+
156
+ before: function beforeHook(id) {
157
+ const hookSegment = segmentMap.get(id)
158
+
159
+ if (!hookSegment) {
160
+ return
161
+ }
162
+
163
+ segmentMap.set(id, shim.getActiveSegment())
164
+ shim.setActiveSegment(hookSegment)
165
+ },
166
+ after: function afterHook(id) {
167
+ const hookSegment = segmentMap.get(id)
168
+
169
+ // hookSegment is the segment that was active before the promise
170
+ // executed. If the promise is executing before a segment has been
171
+ // restored, hookSegment will be null and should be restored. Thus
172
+ // undefined is the only invalid value here.
173
+ if (hookSegment === undefined) {
174
+ return
175
+ }
176
+
177
+ segmentMap.set(id, shim.getActiveSegment())
178
+ shim.setActiveSegment(hookSegment)
179
+ },
180
+ promiseResolve: function promiseResolveHandler(id) {
181
+ const hookSegment = segmentMap.get(id)
182
+ segmentMap.delete(id)
183
+
184
+ if (hookSegment === undefined) {
185
+ return
186
+ }
187
+
188
+ shim.setActiveSegment(hookSegment)
189
+ }
190
+ }
191
+
192
+ return hooks
106
193
  }
@@ -267,6 +267,11 @@ function wrapResponseEnd(agent, proto) {
267
267
  return end.apply(this, arguments)
268
268
  }
269
269
 
270
+ if (!txInfo.transaction.isActive()) {
271
+ logger.trace('wrappedResEnd invoked for ended transaction implying multiple invocations.')
272
+ return end.apply(this, arguments)
273
+ }
274
+
270
275
  // If an error happened, add it to the aggregator.
271
276
  if (txInfo.error) {
272
277
  if (!txInfo.errorHandled || urltils.isError(agent.config, this.statusCode)) {
@@ -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,
package/lib/shim/shim.js CHANGED
@@ -1895,7 +1895,12 @@ function shimRequire(filePath) {
1895
1895
  try {
1896
1896
  return require(path.resolve(this._moduleRoot, filePath))
1897
1897
  } catch (e) {
1898
- this.logger.debug('Failed to load %j: %s', filePath, e.stack)
1898
+ this.logger.debug(
1899
+ 'Failed to load \'%s\' from module root: \'%s\'. Stack: %s',
1900
+ filePath,
1901
+ this._moduleRoot,
1902
+ e.stack
1903
+ )
1899
1904
  return null
1900
1905
  }
1901
1906
  }
@@ -72,6 +72,7 @@ function createStandardAggregator(config, collector, metrics) {
72
72
  }
73
73
 
74
74
  function validateInfiniteTracing(trace_observer) {
75
+ // TODO: Remove semver check when Node 10 support dropped.
75
76
  if (!psemver.satisfies('>=10.10.0')) {
76
77
  logger.warn(
77
78
  'Infinite tracing disabled: this version of Node is not supported (must be >=10.10.0)'
@@ -9,7 +9,7 @@ const Config = require('../config')
9
9
  const {truncate} = require('../util/byte-limit')
10
10
 
11
11
  const {DESTINATIONS} = require('../config/attribute-filter')
12
- const NAMES = require('../metrics/names')
12
+
13
13
  const HTTP_LIBRARY = 'http'
14
14
  const CLIENT_KIND = 'client'
15
15
  const CATEGORIES = {
@@ -18,6 +18,9 @@ const CATEGORIES = {
18
18
  GENERIC: 'generic'
19
19
  }
20
20
 
21
+ const EXTERNAL_REGEX = /^(?:Truncated\/)?External\//
22
+ const DATASTORE_REGEX = /^(?:Truncated\/)?Datastore\//
23
+
21
24
  const EMPTY_USER_ATTRS = Object.freeze(Object.create(null))
22
25
 
23
26
  /**
@@ -200,7 +203,7 @@ class HttpSpanEvent extends SpanEvent {
200
203
  }
201
204
 
202
205
  static testSegment(segment) {
203
- return segment.name.startsWith(NAMES.EXTERNAL.PREFIX)
206
+ return EXTERNAL_REGEX.test(segment.name)
204
207
  }
205
208
  }
206
209
 
@@ -259,7 +262,7 @@ class DatastoreSpanEvent extends SpanEvent {
259
262
  }
260
263
 
261
264
  static testSegment(segment) {
262
- return segment.name.startsWith(NAMES.DB.PREFIX)
265
+ return DATASTORE_REGEX.test(segment.name)
263
266
  }
264
267
  }
265
268
 
@@ -10,7 +10,7 @@ const {truncate} = require('../util/byte-limit')
10
10
  const Config = require('../config')
11
11
 
12
12
  const {DESTINATIONS} = require('../config/attribute-filter')
13
- const NAMES = require('../metrics/names')
13
+
14
14
  const HTTP_LIBRARY = 'http'
15
15
  const CLIENT_KIND = 'client'
16
16
  const CATEGORIES = {
@@ -19,6 +19,9 @@ const CATEGORIES = {
19
19
  GENERIC: 'generic'
20
20
  }
21
21
 
22
+ const EXTERNAL_REGEX = /^(?:Truncated\/)?External\//
23
+ const DATASTORE_REGEX = /^(?:Truncated\/)?Datastore\//
24
+
22
25
  /**
23
26
  * Specialized span event class for use with infinite streaming.
24
27
  * Currently designed to be sent over grpc via the v1.proto definition.
@@ -200,7 +203,7 @@ class StreamingHttpSpanEvent extends StreamingSpanEvent {
200
203
  }
201
204
 
202
205
  static isHttpSegment(segment) {
203
- return segment.name.startsWith(NAMES.EXTERNAL.PREFIX)
206
+ return EXTERNAL_REGEX.test(segment.name)
204
207
  }
205
208
  }
206
209
 
@@ -269,7 +272,7 @@ class StreamingDatastoreSpanEvent extends StreamingSpanEvent {
269
272
  }
270
273
 
271
274
  static isDatastoreSegment(segment) {
272
- return segment.name.startsWith(NAMES.DB.PREFIX)
275
+ return DATASTORE_REGEX.test(segment.name)
273
276
  }
274
277
  }
275
278
 
@@ -225,9 +225,28 @@ Transaction.prototype.end = function end() {
225
225
  }
226
226
 
227
227
  this.agent.emit('transactionFinished', this)
228
+
229
+ // Do after emit so all post-processing can complete
230
+ this._cleanUneededReferences()
231
+
228
232
  return this
229
233
  }
230
234
 
235
+ /**
236
+ * Cleans up references that will not be used later for processing such as
237
+ * transaction traces.
238
+ *
239
+ * Errors won't be needed for later processing but can contain extra details we
240
+ * don't want to hold in memory. Particularly, axios errors can result in indirect
241
+ * references to promises which will prevent them from being destroyed and result
242
+ * in a memory leak. This is due to the TraceSegment not getting removed from the
243
+ * async-hooks segmentMap because 'destroy' never fires.
244
+ */
245
+ Transaction.prototype._cleanUneededReferences = function _cleanUneededReferences() {
246
+ this.userErrors = null
247
+ this.exceptions = null
248
+ }
249
+
231
250
  /**
232
251
  * For web transactions, this represents the time from when the request was received
233
252
  * to when response was sent. For background transactions, it is equal to duration
@@ -768,6 +787,11 @@ function _linkExceptionToSegment(exception) {
768
787
  Transaction.prototype.addException = _addException
769
788
 
770
789
  function _addException(exception) {
790
+ if (!this.isActive()) {
791
+ logger.trace('Transaction is not active. Not capturing error: ', exception)
792
+ return
793
+ }
794
+
771
795
  this._linkExceptionToSegment(exception)
772
796
  this.exceptions.push(exception)
773
797
  }
@@ -782,6 +806,11 @@ function _addException(exception) {
782
806
  Transaction.prototype.addUserError = _addUserError
783
807
 
784
808
  function _addUserError(exception) {
809
+ if (!this.isActive()) {
810
+ logger.trace('Transaction is not active. Not capturing user error: ', exception)
811
+ return
812
+ }
813
+
785
814
  this._linkExceptionToSegment(exception)
786
815
  this.userErrors.push(exception)
787
816
  }
@@ -879,6 +908,13 @@ Transaction.prototype.getIntrinsicAttributes = function getIntrinsicAttributes()
879
908
  */
880
909
  Transaction.prototype.acceptDistributedTraceHeaders = acceptDistributedTraceHeaders
881
910
  function acceptDistributedTraceHeaders(transportType, headers) {
911
+ if (headers == null || typeof headers !== 'object') {
912
+ logger.trace(
913
+ 'Ignoring distributed trace headers for transaction %s. Headers not passed in as object.',
914
+ this.id)
915
+ return
916
+ }
917
+
882
918
  const transport = TRANSPORT_TYPES_SET[transportType] ? transportType : TRANSPORT_TYPES.UNKNOWN
883
919
 
884
920
  // assumes header keys already lowercase
package/newrelic.js CHANGED
@@ -28,7 +28,7 @@ exports.config = {
28
28
  *
29
29
  * @env NEW_RELIC_DISTRIBUTED_TRACING_ENABLED
30
30
  */
31
- enabled: false
31
+ enabled: true
32
32
  },
33
33
  logging: {
34
34
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "7.1.2",
3
+ "version": "7.3.0",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [
@@ -125,7 +125,7 @@
125
125
  "docs": "npm ci && jsdoc -c ./jsdoc-conf.json --private -r .",
126
126
  "integration": "npm run prepare-test && npm run sub-install && time tap --no-esm test/integration/**/**/*.tap.js --timeout=180 --no-coverage",
127
127
  "prepare-test": "npm ci && npm run ca-gen && npm run ssl && npm run docker-env",
128
- "lint": "eslint ./*.js lib test",
128
+ "lint": "eslint ./*.js lib test bin",
129
129
  "public-docs": "npm ci && jsdoc -c ./jsdoc-conf.json --tutorials examples/shim api.js lib/shim/ lib/transaction/handle.js && cp examples/shim/*.png out/",
130
130
  "publish-docs": "./bin/publish-docs.sh",
131
131
  "services": "./bin/docker-services.sh",
@@ -137,15 +137,14 @@
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",
148
- "@grpc/proto-loader": "^0.5.5",
146
+ "@grpc/grpc-js": "^1.2.11",
147
+ "@grpc/proto-loader": "^0.5.6",
149
148
  "@newrelic/aws-sdk": "^3.1.0",
150
149
  "@newrelic/koa": "^5.0.0",
151
150
  "@newrelic/superagent": "^4.0.0",
@@ -199,5 +198,18 @@
199
198
  "repository": {
200
199
  "type": "git",
201
200
  "url": "https://github.com/newrelic/node-newrelic.git"
202
- }
201
+ },
202
+ "files": [
203
+ "index.js",
204
+ "api.js",
205
+ "stub_api.js",
206
+ "newrelic.js",
207
+ "README.md",
208
+ "LICENSE",
209
+ "NEWS.md",
210
+ "THIRD_PARTY_NOTICES.md",
211
+ "lib/",
212
+ "bin/tracetractor",
213
+ "bin/test-naming-rules.js"
214
+ ]
203
215
  }
package/CONTRIBUTING.md DELETED
@@ -1,135 +0,0 @@
1
- # Guidelines for Contributing Code
2
-
3
- New Relic welcomes code contributions by the Node community to this module, and
4
- have taken effort to make this process easy for both contributors and our
5
- development team.
6
-
7
- ## Process
8
-
9
- ### Feature Requests
10
-
11
- Feature requests should be submitted in the [Issue tracker](../../issues), with
12
- a description of the expected behavior & use case. Before submitting an Issue,
13
- please search for similar ones in the [closed
14
- issues](../../issues?q=is%3Aissue+is%3Aclosed+label%3Aenhancement).
15
-
16
- ### Pull Requests
17
-
18
- We can only accept PRs for version v6.11.0 or greater due to open source
19
- licensing restrictions.
20
-
21
- ### Code of Conduct
22
-
23
- Before contributing please read the [code of conduct](https://github.com/newrelic/.github/blob/main/CODE_OF_CONDUCT.md)
24
-
25
- Note that our [code of conduct](https://github.com/newrelic/.github/blob/main/CODE_OF_CONDUCT.md) applies to all platforms
26
- and venues related to this project; please follow it in all your interactions
27
- with the project and its participants.
28
-
29
- ### Contributor License Agreement
30
-
31
- Keep in mind that when you submit your Pull Request, you'll need to sign the
32
- CLA via the click-through using CLA-Assistant. If you'd like to execute our
33
- corporate CLA, or if you have any questions, please drop us an email at
34
- opensource@newrelic.com.
35
-
36
- For more information about CLAs, please check out Alex Russell’s excellent
37
- post, [“Why Do I Need to Sign
38
- This?”](https://infrequently.org/2008/06/why-do-i-need-to-sign-this/).
39
-
40
- ### Slack
41
-
42
- We host a public Slack with a dedicated channel for contributors and
43
- maintainers of open source projects hosted by New Relic. If you are
44
- contributing to this project, you're welcome to request access to the
45
- \#oss-contributors channel in the newrelicusers.slack.com workspace. To request
46
- access, see https://newrelicusers-signup.herokuapp.com/.
47
-
48
- ## PR Guidelines
49
-
50
- ### Version Support
51
-
52
- When contributing, keep in mind that New Relic customers (that's you!) are running many different versions of Node, some of them pretty old. Changes that depend on the newest version of Node will probably be rejected, especially if they replace something backwards compatible.
53
-
54
- Be aware that the instrumentation needs to work with a wide range of versions of the instrumented modules, and that code that looks nonsensical or overcomplicated may be that way for compatibility-related reasons. Read all the comments and check the related tests before deciding whether existing code is incorrect.
55
-
56
- If you’re planning on contributing a new feature or an otherwise complex contribution, we kindly ask you to start a conversation with the maintainer team by opening up an Github issue first.
57
-
58
- ### General Guidelines
59
-
60
- In general, we try to limit adding third-party production dependencies. If one is necessary, please be prepared to make a clear case for the need.
61
-
62
- ### Coding Style Guidelines/Conventions
63
-
64
- We use eslint to enforce certain coding standards. Please see our [.eslintrc](./.eslintrc.js) file for specific rule configuration.
65
-
66
- ### Testing Guidelines
67
-
68
- The agent includes a suite of unit and functional tests which should be used to
69
- verify your changes don't break existing functionality.
70
-
71
- Unit tests are stored in `test/`. They're written in
72
- [node-tap](https://github.com/isaacs/node-tap), and have the extension `.test.js`.
73
-
74
- Generic functional tests are stored in `test/integration/`. They're written in
75
- [node-tap](https://github.com/isaacs/node-tap), and have the extension
76
- `.tap.js`.
77
-
78
- Functional tests against specific versions of instrumented modules are stored
79
- in `test/versioned/`. They are also written in `node-tap`.
80
-
81
- #### Setup
82
-
83
- To run the tests you need an openssl command-line binary, and some services:
84
-
85
- * Cassandra
86
- * Memcached
87
- * MongoDB
88
- * MySQL
89
- * Postgres
90
- * Redis
91
-
92
- If you have these all running locally on the standard ports, then you are good
93
- to go. However, the suggested path is to use [Docker](http://www.docker.com).
94
- If you use macOS or Windows, install [Docker Desktop]
95
- (https://www.docker.com/products/docker-desktop). Then, run `npm run services`
96
- to download and launch docker containers for each of the above services.
97
-
98
- If you have these services available on non-standard ports or elsewhere on your
99
- network, you can use the following environment variables to tell the tests
100
- where they are:
101
-
102
- * NR_NODE\_TEST_&lt;service&gt;\_HOST
103
- * NR_NODE\_TEST_&lt;service&gt;\_PORT
104
-
105
- The service token is the all-caps version of the service name listed above.
106
-
107
- #### Running Tests
108
-
109
- Running the test suite is simple. Just run:
110
-
111
- npm test
112
-
113
- This will install all the necessary modules (and do any required SSL
114
- certificate creation) and run the unit tests in standalone mode, followed by
115
- the functional tests if all of the unit tests pass.
116
-
117
- If you don't feel like dealing with the hassle of setting up the servers, just
118
- the unit tests can be run with:
119
-
120
- npm run unit
121
-
122
- #### Writing Tests
123
-
124
- For most contributions it is strongly recommended to add additional tests which
125
- exercise your changes. This helps us efficiently incorporate your changes into
126
- our mainline codebase and provides a safeguard that your change won't be broken
127
- by future development. Because of this, we require that all changes come with
128
- tests. You are welcome to submit pull requests with untested changes, but they
129
- won't be merged until you or the development team have an opportunity to write
130
- tests for them.
131
-
132
- There are some rare cases where code changes do not result in changed
133
- functionality (e.g. a performance optimization) and new tests are not required.
134
- In general, including tests with your pull request dramatically increases the
135
- chances it will be accepted.