newrelic 12.3.1 → 12.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.
- package/NEWS.md +64 -21
- package/THIRD_PARTY_NOTICES.md +30 -24
- package/lib/agent.js +117 -3
- package/lib/aggregators/base-aggregator.js +182 -3
- package/lib/collector/api.js +38 -3
- package/lib/config/build-instrumentation-config.js +19 -0
- package/lib/config/default.js +8 -1
- package/lib/config/index.js +33 -1
- package/lib/errors/error-collector.js +1 -1
- package/lib/harvester.js +1 -1
- package/lib/metrics/names.js +4 -3
- package/lib/metrics/normalizer.js +9 -0
- package/lib/shim/shim.js +1 -1
- package/lib/shimmer.js +5 -1
- package/lib/spans/streaming-span-event-aggregator.js +27 -2
- package/lib/transaction/index.js +4 -0
- package/lib/transaction/transaction-event-aggregator.js +2 -2
- package/lib/util/stream-sink.js +26 -0
- package/lib/utilization/docker-info.js +8 -72
- package/lib/utilization/ecs-info.js +112 -0
- package/lib/utilization/index.js +4 -3
- package/package.json +2 -2
package/NEWS.md
CHANGED
|
@@ -1,24 +1,67 @@
|
|
|
1
|
-
### v12.
|
|
2
|
-
|
|
3
|
-
####
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
####
|
|
8
|
-
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
### v12.5.0 (2024-09-12)
|
|
2
|
+
|
|
3
|
+
#### Features
|
|
4
|
+
|
|
5
|
+
* Added utilization info for ECS ([#2565](https://github.com/newrelic/node-newrelic/pull/2565)) ([6f92073](https://github.com/newrelic/node-newrelic/commit/6f92073a6c01124d8ab1b54d06c176a36fbc3441))
|
|
6
|
+
|
|
7
|
+
#### Bug fixes
|
|
8
|
+
|
|
9
|
+
* Ensured README displays for Azure site extension ([#2564](https://github.com/newrelic/node-newrelic/pull/2564)) ([a30aed5](https://github.com/newrelic/node-newrelic/commit/a30aed5cf31c0c89678618e51215063562331848))
|
|
10
|
+
|
|
11
|
+
#### Documentation
|
|
12
|
+
|
|
13
|
+
* Updated compatibility report ([#2562](https://github.com/newrelic/node-newrelic/pull/2562)) ([8f7aebe](https://github.com/newrelic/node-newrelic/commit/8f7aebe7e4274ce45cfe961537a09b34077b3aa0))
|
|
14
|
+
|
|
15
|
+
#### Tests
|
|
16
|
+
|
|
17
|
+
* Convert `metric` and `metrics-recorder` tests to `node:test` ([#2552](https://github.com/newrelic/node-newrelic/pull/2552)) ([7ae4af4](https://github.com/newrelic/node-newrelic/commit/7ae4af4c8adfabadd3c865bd2fdd0e8ba5317eef))
|
|
18
|
+
* Updated `serverless` unit tests to `node:test` ([#2549](https://github.com/newrelic/node-newrelic/pull/2549)) ([619f23c](https://github.com/newrelic/node-newrelic/commit/619f23c938bf39c360a6da9a307c178986c70902))
|
|
19
|
+
|
|
20
|
+
### v12.4.0 (2024-09-11)
|
|
21
|
+
|
|
22
|
+
#### Features
|
|
23
|
+
|
|
24
|
+
* Added support for `express@5` ([#2555](https://github.com/newrelic/node-newrelic/pull/2555)) ([252f3b2](https://github.com/newrelic/node-newrelic/commit/252f3b2bc1206dad52d914b98a2352da317da2d5))
|
|
25
|
+
* Provided ability to disable instrumentation for a 3rd party package ([#2551](https://github.com/newrelic/node-newrelic/pull/2551)) ([abfb9f0](https://github.com/newrelic/node-newrelic/commit/abfb9f029a4f6c25966c35d3284ddae0d46dfecb))
|
|
26
|
+
* To disable instrumentation set `config.instrumentation.<library>.enabled` to false. The values of `<library>` are the keys listed [here](https://github.com/newrelic/node-newrelic/blob/main/lib/instrumentations.js)
|
|
27
|
+
* This feature is use at your own risk. Disabling instrumentation for a library could affect instrumentation of other libraries executed afterwards.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
#### Miscellaneous chores
|
|
31
|
+
|
|
32
|
+
* Added CI for publishing agent as Azure site extension ([#2488](https://github.com/newrelic/node-newrelic/pull/2488)) ([468943a](https://github.com/newrelic/node-newrelic/commit/468943a1ed3864dafb93a2f96561d1a778d03a5f))
|
|
33
|
+
* Added Azure site extension installation scripts ([#2448](https://github.com/newrelic/node-newrelic/pull/2448)) ([a56c4e1](https://github.com/newrelic/node-newrelic/commit/a56c4e146ead7d3205fead1f17afad0ea7a77e59))
|
|
34
|
+
|
|
35
|
+
#### Tests
|
|
36
|
+
|
|
37
|
+
* Converted `llm-events` tests to use `node:test` ([#2535](https://github.com/newrelic/node-newrelic/pull/2535)) ([ebfa2e9](https://github.com/newrelic/node-newrelic/commit/ebfa2e9ab8ecbe4bc9adaddd3e4a60e3ba84d0d9))
|
|
38
|
+
* Migrated `test/unit/spans` to use `node:test` ([#2556](https://github.com/newrelic/node-newrelic/pull/2556)) ([9319071](https://github.com/newrelic/node-newrelic/commit/931907182b0168990a04bb92c2f28310450f8ba0))
|
|
39
|
+
* Migrated `test/unit/util` to use `node:test` ([#2546](https://github.com/newrelic/node-newrelic/pull/2546)) ([0b07be8](https://github.com/newrelic/node-newrelic/commit/0b07be8f7f29e67630326c73b96faa5e20527a0b))
|
|
40
|
+
* Migrated tests in `test/unit/instrumentation` to use `node:test` ([#2531](https://github.com/newrelic/node-newrelic/pull/2531)) ([47b8398](https://github.com/newrelic/node-newrelic/commit/47b8398820d665a85a96ae84e30eaaf20564dcf8))
|
|
41
|
+
* Converted `collector` unit tests to `node:test` ([#2510](https://github.com/newrelic/node-newrelic/pull/2510)) ([762511b](https://github.com/newrelic/node-newrelic/commit/762511be524f971a609ff45c111c2d1a89ec1c46))
|
|
42
|
+
* Converted `errors` unit tests to `node:test` ([#2540](https://github.com/newrelic/node-newrelic/pull/2540)) ([ae82760](https://github.com/newrelic/node-newrelic/commit/ae82760f7001f6bcdd6a9fe0ec1e96dc60db99e5))
|
|
43
|
+
|
|
44
|
+
### v12.3.1 (2024-09-04)
|
|
45
|
+
|
|
46
|
+
#### Bug fixes
|
|
47
|
+
|
|
48
|
+
* Fixed detection of REST API type payloads in AWS Lambda ([#2543](https://github.com/newrelic/node-newrelic/pull/2543)) ([adfeebc](https://github.com/newrelic/node-newrelic/commit/adfeebc043161e0e0c35de2cf93989dbde9cb8fa))
|
|
49
|
+
|
|
50
|
+
#### Documentation
|
|
51
|
+
|
|
52
|
+
* Cleaned up formatting of api.js to properly inject example snippets when rendering on API docs site ([#2524](https://github.com/newrelic/node-newrelic/pull/2524)) ([4b34f3d](https://github.com/newrelic/node-newrelic/commit/4b34f3dbab45a55ec447b6e21b69c7621b41e539))
|
|
53
|
+
* Updated compatibility report ([#2523](https://github.com/newrelic/node-newrelic/pull/2523)) ([29784ea](https://github.com/newrelic/node-newrelic/commit/29784ea766b2a9388c050f271ab7190895bc22ed))
|
|
54
|
+
* Updated Next.js Otel cloud provider FAQ ([#2537](https://github.com/newrelic/node-newrelic/pull/2537)) ([6553807](https://github.com/newrelic/node-newrelic/commit/655380760a89193c5b6cd47d3955d1244cd79e7b))
|
|
55
|
+
|
|
56
|
+
#### Tests
|
|
57
|
+
|
|
58
|
+
* Converted db unit tests to node:test ([#2514](https://github.com/newrelic/node-newrelic/pull/2514)) ([bea4548](https://github.com/newrelic/node-newrelic/commit/bea45481a8a04099096929b36532203fbb8b6921))
|
|
59
|
+
* Converted grpc, lib, and utilization tests to `node:test` ([#2532](https://github.com/newrelic/node-newrelic/pull/2532)) ([c207e1e](https://github.com/newrelic/node-newrelic/commit/c207e1e3de75a9c3a2c4a05fa1bc318d3e455ef9))
|
|
60
|
+
* Replaced distributed tracing tests with `node:test` ([#2527](https://github.com/newrelic/node-newrelic/pull/2527)) ([8184c56](https://github.com/newrelic/node-newrelic/commit/8184c5676155b9028c84adc0da3902803ee9d107))
|
|
61
|
+
* Added a match function for tests ([#2541](https://github.com/newrelic/node-newrelic/pull/2541)) ([51e7f34](https://github.com/newrelic/node-newrelic/commit/51e7f34e733202a9c2c024d9d9a7f3c207dfc4b0))
|
|
62
|
+
* Converted `config` to `node:test` ([#2517](https://github.com/newrelic/node-newrelic/pull/2517)) ([1534a73](https://github.com/newrelic/node-newrelic/commit/1534a734995b6800c4cab3b6712f1b6b1329ed5e))
|
|
63
|
+
|
|
64
|
+
|
|
22
65
|
### v12.3.0 (2024-08-27)
|
|
23
66
|
|
|
24
67
|
#### Features
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -34,6 +34,7 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
34
34
|
* [@aws-sdk/client-s3](#aws-sdkclient-s3)
|
|
35
35
|
* [@aws-sdk/s3-request-presigner](#aws-sdks3-request-presigner)
|
|
36
36
|
* [@koa/router](#koarouter)
|
|
37
|
+
* [@matteo.collina/tspl](#matteocollinatspl)
|
|
37
38
|
* [@newrelic/eslint-config](#newreliceslint-config)
|
|
38
39
|
* [@newrelic/newrelic-oss-cli](#newrelicnewrelic-oss-cli)
|
|
39
40
|
* [@newrelic/test-utilities](#newrelictest-utilities)
|
|
@@ -69,7 +70,6 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
69
70
|
* [nock](#nock)
|
|
70
71
|
* [proxy](#proxy)
|
|
71
72
|
* [proxyquire](#proxyquire)
|
|
72
|
-
* [rfdc](#rfdc)
|
|
73
73
|
* [rimraf](#rimraf)
|
|
74
74
|
* [self-cert](#self-cert)
|
|
75
75
|
* [should](#should)
|
|
@@ -1521,6 +1521,35 @@ THE SOFTWARE.
|
|
|
1521
1521
|
|
|
1522
1522
|
```
|
|
1523
1523
|
|
|
1524
|
+
### @matteo.collina/tspl
|
|
1525
|
+
|
|
1526
|
+
This product includes source derived from [@matteo.collina/tspl](https://github.com/mcollina/tspl) ([v0.1.1](https://github.com/mcollina/tspl/tree/v0.1.1)), distributed under the [MIT License](https://github.com/mcollina/tspl/blob/v0.1.1/LICENSE):
|
|
1527
|
+
|
|
1528
|
+
```
|
|
1529
|
+
MIT License
|
|
1530
|
+
|
|
1531
|
+
Copyright (c) 2023 Matteo Collina
|
|
1532
|
+
|
|
1533
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1534
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
1535
|
+
in the Software without restriction, including without limitation the rights
|
|
1536
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1537
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
1538
|
+
furnished to do so, subject to the following conditions:
|
|
1539
|
+
|
|
1540
|
+
The above copyright notice and this permission notice shall be included in all
|
|
1541
|
+
copies or substantial portions of the Software.
|
|
1542
|
+
|
|
1543
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1544
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1545
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1546
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1547
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1548
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1549
|
+
SOFTWARE.
|
|
1550
|
+
|
|
1551
|
+
```
|
|
1552
|
+
|
|
1524
1553
|
### @newrelic/eslint-config
|
|
1525
1554
|
|
|
1526
1555
|
This product includes source derived from [@newrelic/eslint-config](https://github.com/newrelic/eslint-config-newrelic) ([v0.3.0](https://github.com/newrelic/eslint-config-newrelic/tree/v0.3.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/eslint-config-newrelic/blob/v0.3.0/LICENSE):
|
|
@@ -3978,29 +4007,6 @@ OTHER DEALINGS IN THE SOFTWARE.
|
|
|
3978
4007
|
|
|
3979
4008
|
```
|
|
3980
4009
|
|
|
3981
|
-
### rfdc
|
|
3982
|
-
|
|
3983
|
-
This product includes source derived from [rfdc](https://github.com/davidmarkclements/rfdc) ([v1.4.1](https://github.com/davidmarkclements/rfdc/tree/v1.4.1)), distributed under the [MIT License](https://github.com/davidmarkclements/rfdc/blob/v1.4.1/LICENSE):
|
|
3984
|
-
|
|
3985
|
-
```
|
|
3986
|
-
Copyright 2019 "David Mark Clements <david.mark.clements@gmail.com>"
|
|
3987
|
-
|
|
3988
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
3989
|
-
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
3990
|
-
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
3991
|
-
to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
3992
|
-
|
|
3993
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions
|
|
3994
|
-
of the Software.
|
|
3995
|
-
|
|
3996
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
3997
|
-
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
3998
|
-
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
3999
|
-
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
4000
|
-
IN THE SOFTWARE.
|
|
4001
|
-
|
|
4002
|
-
```
|
|
4003
|
-
|
|
4004
4010
|
### rimraf
|
|
4005
4011
|
|
|
4006
4012
|
This product includes source derived from [rimraf](https://github.com/isaacs/rimraf) ([v2.7.1](https://github.com/isaacs/rimraf/tree/v2.7.1)), distributed under the [ISC License](https://github.com/isaacs/rimraf/blob/v2.7.1/LICENSE):
|
package/lib/agent.js
CHANGED
|
@@ -57,6 +57,94 @@ const MAX_ERROR_TRACES_DEFAULT = 20
|
|
|
57
57
|
const INITIAL_HARVEST_DELAY_MS = 1000
|
|
58
58
|
const DEFAULT_HARVEST_INTERVAL_MS = 60000
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Indicates that the agent has finished connecting. It is preceded by
|
|
62
|
+
* {@link Agent#event:connecting}.
|
|
63
|
+
*
|
|
64
|
+
* @event Agent#connected
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Indicates that the agent is in the connecting state. That is, it is
|
|
69
|
+
* communicating with the New Relic data collector and performing requisite
|
|
70
|
+
* operations before the agent is ready to collect and send data.
|
|
71
|
+
*
|
|
72
|
+
* @event Agent#connecting
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Indicates that the agent has terminated, or lost, its connection to the
|
|
77
|
+
* New Relic data collector.
|
|
78
|
+
*
|
|
79
|
+
* @event Agent#disconnected
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Indicates that the agent has encountered, or generated, some error that
|
|
84
|
+
* prevents it from operating correctly. The agent state will be set to
|
|
85
|
+
* "errored."
|
|
86
|
+
*
|
|
87
|
+
* @event Agent#errored
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Indicates that the synchronous harvest cycle has completed. This will be
|
|
92
|
+
* prefaced by the {@link Agent#event:harvestStarted} event. It is only fired
|
|
93
|
+
* in a serverless context.
|
|
94
|
+
*
|
|
95
|
+
* @event Agent#harvestFinished
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Indicates that a synchronous harvest cycle (collecting data from the various
|
|
100
|
+
* aggregators and sending said data to the New Relic data collector) has
|
|
101
|
+
* started. This is only fired in a serverless context.
|
|
102
|
+
*
|
|
103
|
+
* @event Agent#harvestStarted
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Indicates that the agent state has entered the "started" state. That is,
|
|
108
|
+
* the agent has finished bootstrapping and is collecting and sending data.
|
|
109
|
+
*
|
|
110
|
+
* @event Agent#started
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Indicates that the agent is starting. This is typically the first event
|
|
115
|
+
* emitted by the agent.
|
|
116
|
+
*
|
|
117
|
+
* @event Agent#starting
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Indicates that the agent state has changed to the "stopped" state. That is,
|
|
122
|
+
* the agent is no longer collecting or sending data.
|
|
123
|
+
*
|
|
124
|
+
* @event Agent#stopped
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Indicates that the agent is entering its shutdown process.
|
|
129
|
+
*
|
|
130
|
+
* @event Agent#stopping
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Indicates that the transaction has begun recording data.
|
|
135
|
+
*
|
|
136
|
+
* @event Agent#transactionStarted
|
|
137
|
+
* @param {Transaction} currentTransaction
|
|
138
|
+
*/
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Indicates that the transaction has stopped recording data and has been
|
|
142
|
+
* closed.
|
|
143
|
+
*
|
|
144
|
+
* @event Agent#transactionFinished
|
|
145
|
+
* @param {Transaction} currentTransaction
|
|
146
|
+
*/
|
|
147
|
+
|
|
60
148
|
/**
|
|
61
149
|
* There's a lot of stuff in this constructor, due to Agent acting as the
|
|
62
150
|
* orchestrator for New Relic within instrumented applications.
|
|
@@ -101,7 +189,7 @@ function Agent(config) {
|
|
|
101
189
|
this.harvester
|
|
102
190
|
)
|
|
103
191
|
|
|
104
|
-
this.metrics.on('
|
|
192
|
+
this.metrics.on('starting_data_send-metric_data', this._beforeMetricDataSend.bind(this))
|
|
105
193
|
|
|
106
194
|
this.spanEventAggregator = createSpanEventAggregator(config, this)
|
|
107
195
|
|
|
@@ -226,6 +314,12 @@ util.inherits(Agent, EventEmitter)
|
|
|
226
314
|
*
|
|
227
315
|
* @param {Function} callback Continuation and error handler.
|
|
228
316
|
* @returns {void}
|
|
317
|
+
*
|
|
318
|
+
* @fires Agent#errored When configuration is not sufficient for operations or
|
|
319
|
+
* cannot establish a connection to the data collector.
|
|
320
|
+
* @fires Agent#starting
|
|
321
|
+
* @fires Agent#stopped When configuration indicates that the agent should be
|
|
322
|
+
* disabled.
|
|
229
323
|
*/
|
|
230
324
|
Agent.prototype.start = function start(callback) {
|
|
231
325
|
if (!callback) {
|
|
@@ -306,6 +400,8 @@ Agent.prototype.startStreaming = function startStreaming() {
|
|
|
306
400
|
*
|
|
307
401
|
* @param {boolean} shouldImmediatelyHarvest Whether we should immediately schedule a harvest, or wait a cycle
|
|
308
402
|
* @param {Function} callback callback function that executes after harvest completes (now if immediate, otherwise later)
|
|
403
|
+
*
|
|
404
|
+
* @fires Agent#started
|
|
309
405
|
*/
|
|
310
406
|
Agent.prototype.onConnect = function onConnect(shouldImmediatelyHarvest, callback) {
|
|
311
407
|
this.harvester.update(this.config)
|
|
@@ -368,6 +464,11 @@ Agent.prototype._serverlessModeStart = function _serverlessModeStart(callback) {
|
|
|
368
464
|
* current instrumentation and patch to the module loader.
|
|
369
465
|
*
|
|
370
466
|
* @param {Function} callback callback function to invoke after agent stop
|
|
467
|
+
*
|
|
468
|
+
* @fires Agent#errored When disconnecting from the data collector has resulted
|
|
469
|
+
* in some error.
|
|
470
|
+
* @fires Agent#stopped
|
|
471
|
+
* @fires Agent#stopping
|
|
371
472
|
*/
|
|
372
473
|
Agent.prototype.stop = function stop(callback) {
|
|
373
474
|
if (!callback) {
|
|
@@ -432,9 +533,13 @@ Agent.prototype._resetCustomEvents = function resetCustomEvents() {
|
|
|
432
533
|
}
|
|
433
534
|
|
|
434
535
|
/**
|
|
435
|
-
* This method invokes a harvest synchronously.
|
|
536
|
+
* This method invokes a harvest synchronously, i.e. sends all data to the
|
|
537
|
+
* New Relic collector in a blocking fashion.
|
|
538
|
+
*
|
|
539
|
+
* NOTE: this doesn't currently work outside serverless mode.
|
|
436
540
|
*
|
|
437
|
-
*
|
|
541
|
+
* @fires Agent#harvestStarted
|
|
542
|
+
* @fires Agent#harvestFinished
|
|
438
543
|
*/
|
|
439
544
|
Agent.prototype.harvestSync = function harvestSync() {
|
|
440
545
|
logger.trace('Peparing to harvest.')
|
|
@@ -518,6 +623,15 @@ Agent.prototype.reconfigure = function reconfigure(configuration) {
|
|
|
518
623
|
* creation of Transactions.
|
|
519
624
|
*
|
|
520
625
|
* @param {string} newState The new state of the agent.
|
|
626
|
+
*
|
|
627
|
+
* @fires Agent#connected
|
|
628
|
+
* @fires Agent#connecting
|
|
629
|
+
* @fires Agent#disconnected
|
|
630
|
+
* @fires Agent#errored
|
|
631
|
+
* @fires Agent#started
|
|
632
|
+
* @fires Agent#starting
|
|
633
|
+
* @fires Agent#stopped
|
|
634
|
+
* @fires Agent#stopping
|
|
521
635
|
*/
|
|
522
636
|
Agent.prototype.setState = function setState(newState) {
|
|
523
637
|
if (!STATES.hasOwnProperty(newState)) {
|
|
@@ -8,6 +8,152 @@
|
|
|
8
8
|
const EventEmitter = require('events').EventEmitter
|
|
9
9
|
const logger = require('../logger').child({ component: 'base_aggregator' })
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Triggered when the aggregator has finished sending data to the
|
|
13
|
+
* `analytic_event_data` collector endpoint.
|
|
14
|
+
*
|
|
15
|
+
* @event Aggregator#finished_data_send-analytic_event_data
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Triggered when an aggregator is sending data to the `analytic_event_data`
|
|
20
|
+
* collector endpoint.
|
|
21
|
+
*
|
|
22
|
+
* @event Aggregator#starting_data_send-analytic_event_data
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Triggered when the aggregator has finished sending data to the
|
|
27
|
+
* `custom_event_data` collector endpoint.
|
|
28
|
+
*
|
|
29
|
+
* @event Aggregator#finished_data_send-custom_event_data
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Triggered when an aggregator is sending data to the `custom_event_data`
|
|
34
|
+
* collector endpoint.
|
|
35
|
+
*
|
|
36
|
+
* @event Aggregator#starting_data_send-custom_event_data
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Triggered when the aggregator has finished sending data to the
|
|
41
|
+
* `error_data` collector endpoint.
|
|
42
|
+
*
|
|
43
|
+
* @event Aggregator#finished_data_send-error_data
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Triggered when an aggregator is sending data to the `error_data`
|
|
48
|
+
* collector endpoint.
|
|
49
|
+
*
|
|
50
|
+
* @event Aggregator#starting_data_send-error_data
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Triggered when the aggregator has finished sending data to the
|
|
55
|
+
* `error_event_data` collector endpoint.
|
|
56
|
+
*
|
|
57
|
+
* @event Aggregator#finished_data_send-error_event_data
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Triggered when an aggregator is sending data to the `error_event_data`
|
|
62
|
+
* collector endpoint.
|
|
63
|
+
*
|
|
64
|
+
* @event Aggregator#starting_data_send-error_event_data
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Triggered when the aggregator has finished sending data to the
|
|
69
|
+
* `log_event_data` collector endpoint.
|
|
70
|
+
*
|
|
71
|
+
* @event Aggregator#finished_data_send-log_event_data
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Triggered when an aggregator is sending data to the `log_event_data`
|
|
76
|
+
* collector endpoint.
|
|
77
|
+
*
|
|
78
|
+
* @event Aggregator#starting_data_send-log_event_data
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Triggered when the aggregator has finished sending data to the
|
|
83
|
+
* `metric_data` collector endpoint.
|
|
84
|
+
*
|
|
85
|
+
* @event Aggregator#finished_data_send-metric_data
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Triggered when an aggregator is sending data to the `metric_data`
|
|
90
|
+
* collector endpoint.
|
|
91
|
+
*
|
|
92
|
+
* @event Aggregator#starting_data_send-metric_data
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Triggered when the aggregator has finished sending data to the
|
|
97
|
+
* `span_event_data` collector endpoint.
|
|
98
|
+
*
|
|
99
|
+
* @event Aggregator#finished_data_send-span_event_data
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Triggered when an aggregator is sending data to the `span_event_data`
|
|
104
|
+
* collector endpoint.
|
|
105
|
+
*
|
|
106
|
+
* @event Aggregator#starting_data_send-span_event_data
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Triggered when the aggregator has finished sending data to the
|
|
111
|
+
* `sql_trace_data` collector endpoint.
|
|
112
|
+
*
|
|
113
|
+
* @event Aggregator#finished_data_send-sql_trace_data
|
|
114
|
+
*/
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Triggered when an aggregator is sending data to the `sql_trace_data`
|
|
118
|
+
* collector endpoint.
|
|
119
|
+
*
|
|
120
|
+
* @event Aggregator#starting_data_send-sql_trace_data
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Triggered when the aggregator has finished sending data to the
|
|
125
|
+
* `transaction_sample_data` collector endpoint.
|
|
126
|
+
*
|
|
127
|
+
* @event Aggregator#finished_data_send-transaction_sample_data
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Triggered when an aggregator is sending data to the `transaction_sample_data`
|
|
132
|
+
* collector endpoint.
|
|
133
|
+
*
|
|
134
|
+
* @event Aggregator#starting_data_send-transaction_sample_data
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Baseline data aggregator that is used to ship data to the New Relic
|
|
139
|
+
* data collector. Specific data aggregators, e.g. an errors aggregator,
|
|
140
|
+
* extend this base object.
|
|
141
|
+
*
|
|
142
|
+
* Aggregators fire of several events. The events are named according to the
|
|
143
|
+
* pattern `<finished|starting>_data_send-<endpoint_name>`. As an example,
|
|
144
|
+
* if the aggregator is collecting data to send to the `error_event_data`
|
|
145
|
+
* endpoint, there will be two events:
|
|
146
|
+
*
|
|
147
|
+
* + `starting_data_send-error_event_data`
|
|
148
|
+
* + `finished_data_send-error_event_data`
|
|
149
|
+
*
|
|
150
|
+
* For a list of possible endpoints, see
|
|
151
|
+
* {@link https://source.datanerd.us/agents/agent-specs/tree/main/endpoints/protocol-version-17}.
|
|
152
|
+
*
|
|
153
|
+
* Note: effort has been made to document the events for every endpoint this
|
|
154
|
+
* agent interacts with, but due to the dynamic nature of the event names we
|
|
155
|
+
* may have missed some.
|
|
156
|
+
*/
|
|
11
157
|
class Aggregator extends EventEmitter {
|
|
12
158
|
constructor(opts, collector, harvester) {
|
|
13
159
|
super()
|
|
@@ -23,6 +169,16 @@ class Aggregator extends EventEmitter {
|
|
|
23
169
|
return true
|
|
24
170
|
}
|
|
25
171
|
this.enabled = this.isEnabled(opts.config)
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* The name of the collector endpoint that the
|
|
175
|
+
* aggregator will communicate with.
|
|
176
|
+
*
|
|
177
|
+
* @see https://source.datanerd.us/agents/agent-specs/tree/main/endpoints/protocol-version-17
|
|
178
|
+
*
|
|
179
|
+
* @type {string}
|
|
180
|
+
* @memberof Aggregator
|
|
181
|
+
*/
|
|
26
182
|
this.method = opts.method
|
|
27
183
|
this.collector = collector
|
|
28
184
|
this.sendTimer = null
|
|
@@ -90,7 +246,7 @@ class Aggregator extends EventEmitter {
|
|
|
90
246
|
_runSend(data, payload) {
|
|
91
247
|
if (!payload) {
|
|
92
248
|
this._afterSend(false)
|
|
93
|
-
this.emit(`
|
|
249
|
+
this.emit(`finished_data_send-${this.method}`)
|
|
94
250
|
return
|
|
95
251
|
}
|
|
96
252
|
|
|
@@ -102,13 +258,36 @@ class Aggregator extends EventEmitter {
|
|
|
102
258
|
|
|
103
259
|
// TODO: Log?
|
|
104
260
|
this._afterSend(true)
|
|
105
|
-
this.emit(`
|
|
261
|
+
this.emit(`finished_data_send-${this.method}`)
|
|
106
262
|
})
|
|
107
263
|
}
|
|
108
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Serialize all collected data and ship it off to the New Relic data
|
|
267
|
+
* collector. The target endpoint is defined by {@link Aggregator#method}.
|
|
268
|
+
*
|
|
269
|
+
* @fires Aggregator#finished_data_send-analytic_event_data
|
|
270
|
+
* @fires Aggregator#starting_data_send-analytic_event_data
|
|
271
|
+
* @fires Aggregator#finished_data_send-custom_event_data
|
|
272
|
+
* @fires Aggregator#starting_data_send-custom_event_data
|
|
273
|
+
* @fires Aggregator#finished_data_send-error_data
|
|
274
|
+
* @fires Aggregator#starting_data_send-error_data
|
|
275
|
+
* @fires Aggregator#finished_data_send-error_event_data
|
|
276
|
+
* @fires Aggregator#starting_data_send-error_event_data
|
|
277
|
+
* @fires Aggregator#finished_data_send-log_event_data
|
|
278
|
+
* @fires Aggregator#starting_data_send-log_event_data
|
|
279
|
+
* @fires Aggregator#finished_data_send-metric_data
|
|
280
|
+
* @fires Aggregator#starting_data_send-metric_data
|
|
281
|
+
* @fires Aggregator#finished_data_send-span_event_data
|
|
282
|
+
* @fires Aggregator#starting_data_send-span_event_data
|
|
283
|
+
* @fires Aggregator#finished_data_send-sql_trace_data
|
|
284
|
+
* @fires Aggregator#starting_data_send-sql_trace_data
|
|
285
|
+
* @fires Aggregator#finished_data_send-transaction_sample_data
|
|
286
|
+
* @fires Aggregator#starting_data_send-transaction_sample_data
|
|
287
|
+
*/
|
|
109
288
|
send() {
|
|
110
289
|
logger.debug(`${this.method} Aggregator data send.`)
|
|
111
|
-
this.emit(`
|
|
290
|
+
this.emit(`starting_data_send-${this.method}`)
|
|
112
291
|
|
|
113
292
|
const data = this._getMergeData()
|
|
114
293
|
if (this.isAsync) {
|
package/lib/collector/api.js
CHANGED
|
@@ -30,9 +30,29 @@ const BACKOFFS = [
|
|
|
30
30
|
|
|
31
31
|
// Expected collector response codes
|
|
32
32
|
const SUCCESS = new Set([200, 202])
|
|
33
|
-
const RESTART = new Set([
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const RESTART = new Set([
|
|
34
|
+
401, // Authentication failed.
|
|
35
|
+
409 // NR says to reconnect for some reason.
|
|
36
|
+
])
|
|
37
|
+
const FAILURE_SAVE_DATA = new Set([
|
|
38
|
+
408, // Data took too long to reach NR.
|
|
39
|
+
429, // Too many requests being received by NR, rate limited.
|
|
40
|
+
500, // NR server went boom.
|
|
41
|
+
503 // NR server is not available.
|
|
42
|
+
])
|
|
43
|
+
const FAILURE_DISCARD_DATA = new Set([
|
|
44
|
+
400, // Format of the request is incorrect.
|
|
45
|
+
403, // Not entitled to perform the action.
|
|
46
|
+
404, // Sending to wrong destination.
|
|
47
|
+
405, // Using the wrong HTTP method (e.g. PUT instead of POST).
|
|
48
|
+
407, // Proxy authentication misconfigured.
|
|
49
|
+
411, // No Content-Length header provided, or value is incorrect.
|
|
50
|
+
413, // Payload is too large.
|
|
51
|
+
414, // URI exceeds allowed length.
|
|
52
|
+
415, // Content-type or Content-encoding values are incorrect.
|
|
53
|
+
417, // NR cannot meet the expectation of the request.
|
|
54
|
+
431 // Request headers exceed size limit.
|
|
55
|
+
])
|
|
36
56
|
|
|
37
57
|
const AGENT_RUN_BEHAVIOR = CollectorResponse.AGENT_RUN_BEHAVIOR
|
|
38
58
|
|
|
@@ -130,6 +150,17 @@ CollectorAPI.prototype._updateEndpoints = function _updateEndpoints(endpoint) {
|
|
|
130
150
|
}
|
|
131
151
|
}
|
|
132
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Connect to the data collector.
|
|
155
|
+
*
|
|
156
|
+
* @param {function} callback A typical error first callback to be invoked
|
|
157
|
+
* upon successful or unsuccessful connection. The second parameter will be
|
|
158
|
+
* an instance of {@link CollectorResponse}.
|
|
159
|
+
*
|
|
160
|
+
* @fires Agent#connected By way of the full connection process. This event
|
|
161
|
+
* is not fired directly in this method.
|
|
162
|
+
* @fires Agent#connecting
|
|
163
|
+
*/
|
|
133
164
|
CollectorAPI.prototype.connect = function connect(callback) {
|
|
134
165
|
if (!callback) {
|
|
135
166
|
this._throwCallbackError()
|
|
@@ -347,6 +378,8 @@ CollectorAPI.prototype._connect = function _connect(env, callback) {
|
|
|
347
378
|
* @param {Function} callback function to run after processing response
|
|
348
379
|
* @param {Error} error collector response error
|
|
349
380
|
* @param {http.ServerOptions} res collector response
|
|
381
|
+
*
|
|
382
|
+
* @fires Agent#connected
|
|
350
383
|
*/
|
|
351
384
|
CollectorAPI.prototype._onConnect = function _onConnect(callback, error, res) {
|
|
352
385
|
const agent = this._agent
|
|
@@ -431,6 +464,8 @@ CollectorAPI.prototype.shutdown = function shutdown(callback) {
|
|
|
431
464
|
/**
|
|
432
465
|
* @param {Error} error response error
|
|
433
466
|
* @param {http.ServerResponse} response response from collector
|
|
467
|
+
*
|
|
468
|
+
* @fires Agent#disconnected
|
|
434
469
|
*/
|
|
435
470
|
function onShutdown(error, response) {
|
|
436
471
|
if (error) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
const { boolean } = require('./formatters')
|
|
8
|
+
const instrumentedLibraries = require('../instrumentations')()
|
|
9
|
+
const pkgNames = Object.keys(instrumentedLibraries)
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Builds the stanza for config.instrumentation.*
|
|
13
|
+
* It defaults every library to true and assigns a boolean
|
|
14
|
+
* formatter for the environment variable conversion of the values
|
|
15
|
+
*/
|
|
16
|
+
module.exports = pkgNames.reduce((config, pkg) => {
|
|
17
|
+
config[pkg] = { enabled: { formatter: boolean, default: true } }
|
|
18
|
+
return config
|
|
19
|
+
}, {})
|
package/lib/config/default.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const defaultConfig = module.exports
|
|
9
9
|
const { array, int, float, boolean, object, objectList, allowList, regex } = require('./formatters')
|
|
10
|
+
const pkgInstrumentation = require('./build-instrumentation-config')
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* A function that returns the definition of the agent configuration
|
|
@@ -1382,7 +1383,13 @@ defaultConfig.definition = () => ({
|
|
|
1382
1383
|
default: true
|
|
1383
1384
|
}
|
|
1384
1385
|
}
|
|
1385
|
-
}
|
|
1386
|
+
},
|
|
1387
|
+
/**
|
|
1388
|
+
* Stanza that contains all keys to disable 3rd party package instrumentation(i.e. mongodb, pg, redis, etc)
|
|
1389
|
+
* Note: Disabling a given 3rd party library may affect the instrumentation of 3rd party libraries used after
|
|
1390
|
+
* the disabled library.
|
|
1391
|
+
*/
|
|
1392
|
+
instrumentation: pkgInstrumentation
|
|
1386
1393
|
})
|
|
1387
1394
|
|
|
1388
1395
|
/**
|
package/lib/config/index.js
CHANGED
|
@@ -70,6 +70,32 @@ function _findConfigFile() {
|
|
|
70
70
|
return configFileCandidates.find(exists)
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Indicates if the agent should be enabled or disabled based upon the
|
|
75
|
+
* processed configuration.
|
|
76
|
+
*
|
|
77
|
+
* @event Config#agent_enabled
|
|
78
|
+
* @param {boolean} indication
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Indicates that the configuration has changed due to some external factor,
|
|
83
|
+
* e.g. the configuration from the New Relic server has overridden some
|
|
84
|
+
* local setting.
|
|
85
|
+
*
|
|
86
|
+
* @event Config#change
|
|
87
|
+
* @param {Config} currentConfig
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Parses and manages the agent configuration.
|
|
92
|
+
*
|
|
93
|
+
* @param {object} config Configuration object as read from a `newrelic.js`
|
|
94
|
+
* file. This is used as the baseline, which is the overridden by environment
|
|
95
|
+
* variables and feature flags.
|
|
96
|
+
*
|
|
97
|
+
* @class
|
|
98
|
+
*/
|
|
73
99
|
function Config(config) {
|
|
74
100
|
EventEmitter.call(this)
|
|
75
101
|
|
|
@@ -194,6 +220,10 @@ Config.prototype.mergeServerConfig = mergeServerConfig
|
|
|
194
220
|
*
|
|
195
221
|
* @param {object} json The config blob sent by New Relic.
|
|
196
222
|
* @param {boolean} recursion flag indicating coming from server side config
|
|
223
|
+
*
|
|
224
|
+
* @fires Config#agent_enabled When there is a conflict between the local
|
|
225
|
+
* setting of high security mode and what the New Relic server has returned.
|
|
226
|
+
* @fires Config#change
|
|
197
227
|
*/
|
|
198
228
|
Config.prototype.onConnect = function onConnect(json, recursion) {
|
|
199
229
|
json = json || Object.create(null)
|
|
@@ -274,6 +304,8 @@ Config.prototype._updateHarvestConfig = function _updateHarvestConfig(serverConf
|
|
|
274
304
|
*
|
|
275
305
|
* @param {object} params A configuration dictionary.
|
|
276
306
|
* @param {string} key The particular configuration parameter to set.
|
|
307
|
+
*
|
|
308
|
+
* @fires Config#change
|
|
277
309
|
*/
|
|
278
310
|
Config.prototype._fromServer = function _fromServer(params, key) {
|
|
279
311
|
/* eslint-disable-next-line sonarjs/max-switch-cases */
|
|
@@ -839,7 +871,7 @@ Config.prototype.logUnknown = function logUnknown(json, key) {
|
|
|
839
871
|
/**
|
|
840
872
|
* Gets the user set host display name. If not provided, it returns the default value.
|
|
841
873
|
*
|
|
842
|
-
* This function is written
|
|
874
|
+
* This function is written in this strange way because of the use of caching variables.
|
|
843
875
|
* I wanted to cache the DisplayHost, but if I attached the variable to the config object,
|
|
844
876
|
* it sends the extra variable to New Relic, which is not desired.
|
|
845
877
|
*
|
|
@@ -35,7 +35,7 @@ class ErrorCollector {
|
|
|
35
35
|
this.seenObjectsByTransaction = Object.create(null)
|
|
36
36
|
this.seenStringsByTransaction = Object.create(null)
|
|
37
37
|
|
|
38
|
-
this.traceAggregator.on('
|
|
38
|
+
this.traceAggregator.on('starting_data_send-error_data', this._onSendErrorTrace.bind(this))
|
|
39
39
|
|
|
40
40
|
this.errorGroupCallback = null
|
|
41
41
|
}
|
package/lib/harvester.js
CHANGED
|
@@ -37,7 +37,7 @@ module.exports = class Harvester {
|
|
|
37
37
|
this.aggregators.map((aggregator) => {
|
|
38
38
|
return new Promise((resolve) => {
|
|
39
39
|
if (aggregator.enabled) {
|
|
40
|
-
aggregator.once(`
|
|
40
|
+
aggregator.once(`finished_data_send-${aggregator.method}`, function finish() {
|
|
41
41
|
resolve()
|
|
42
42
|
})
|
|
43
43
|
|
package/lib/metrics/names.js
CHANGED
|
@@ -204,11 +204,12 @@ const HAPI = {
|
|
|
204
204
|
|
|
205
205
|
const UTILIZATION = {
|
|
206
206
|
AWS_ERROR: SUPPORTABILITY.UTILIZATION + '/aws/error',
|
|
207
|
-
PCF_ERROR: SUPPORTABILITY.UTILIZATION + '/pcf/error',
|
|
208
207
|
AZURE_ERROR: SUPPORTABILITY.UTILIZATION + '/azure/error',
|
|
209
|
-
|
|
208
|
+
BOOT_ID_ERROR: SUPPORTABILITY.UTILIZATION + '/boot_id/error',
|
|
210
209
|
DOCKER_ERROR: SUPPORTABILITY.UTILIZATION + '/docker/error',
|
|
211
|
-
|
|
210
|
+
ECS_CONTAINER_ERROR: SUPPORTABILITY.UTILIZATION + '/ecs/container_id/error',
|
|
211
|
+
GCP_ERROR: SUPPORTABILITY.UTILIZATION + '/gcp/error',
|
|
212
|
+
PCF_ERROR: SUPPORTABILITY.UTILIZATION + '/pcf/error'
|
|
212
213
|
}
|
|
213
214
|
|
|
214
215
|
const CUSTOM_EVENTS = {
|
|
@@ -32,6 +32,13 @@ function plain(normalized, path) {
|
|
|
32
32
|
return path
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* @event MetricNormalizer#appliedRule
|
|
37
|
+
* @param {object} rule The rule that matched and was applied.
|
|
38
|
+
* @param {string} normalized The newly updated metric name.
|
|
39
|
+
* @param {string} last The metric name that matched the rule.
|
|
40
|
+
*/
|
|
41
|
+
|
|
35
42
|
/**
|
|
36
43
|
* The collector keeps track of rules that should be applied to metric names,
|
|
37
44
|
* and sends these rules to the agent at connection time. These rules can
|
|
@@ -206,6 +213,8 @@ MetricNormalizer.prototype.addSimple = function addSimple(pattern, name) {
|
|
|
206
213
|
*
|
|
207
214
|
* @param {string} path - The URL path to turn into a name.
|
|
208
215
|
* @returns {NormalizationResults} - The results of normalization.
|
|
216
|
+
*
|
|
217
|
+
* @fires MetricNormalizer#appliedRule
|
|
209
218
|
*/
|
|
210
219
|
MetricNormalizer.prototype.normalize = function normalize(path) {
|
|
211
220
|
let last = path
|
package/lib/shim/shim.js
CHANGED
|
@@ -1300,7 +1300,7 @@ function getName(obj) {
|
|
|
1300
1300
|
* @returns {boolean} True if the object is an Object, else false.
|
|
1301
1301
|
*/
|
|
1302
1302
|
function isObject(obj) {
|
|
1303
|
-
return obj instanceof Object
|
|
1303
|
+
return obj != null && (obj instanceof Object || (!obj.constructor && typeof obj === 'object'))
|
|
1304
1304
|
}
|
|
1305
1305
|
|
|
1306
1306
|
/**
|
package/lib/shimmer.js
CHANGED
|
@@ -286,7 +286,11 @@ const shimmer = (module.exports = {
|
|
|
286
286
|
*/
|
|
287
287
|
registerThirdPartyInstrumentation(agent) {
|
|
288
288
|
for (const [moduleName, instrInfo] of Object.entries(INSTRUMENTATIONS)) {
|
|
289
|
-
if (
|
|
289
|
+
if (agent.config.instrumentation?.[moduleName]?.enabled === false) {
|
|
290
|
+
logger.warn(
|
|
291
|
+
`Instrumentation for ${moduleName} has been disabled via 'config.instrumentation.${moduleName}.enabled. Not instrumenting package`
|
|
292
|
+
)
|
|
293
|
+
} else if (instrInfo.module) {
|
|
290
294
|
// Because external instrumentations can change independent of
|
|
291
295
|
// the agent core, we don't want breakages in them to entirely
|
|
292
296
|
// disable the agent.
|
|
@@ -13,8 +13,23 @@ const SEND_WARNING =
|
|
|
13
13
|
'send() is not currently supported on streaming span event aggregator. ' +
|
|
14
14
|
'This warning will not appear again this agent run.'
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Indicates that span streaming has begun.
|
|
18
|
+
*
|
|
19
|
+
* @event StreamingSpanEventAggregator#started
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Indicates that span streaming has finished.
|
|
24
|
+
*
|
|
25
|
+
* @event StreamingSpanEventAggregator#stopped
|
|
26
|
+
*/
|
|
27
|
+
|
|
16
28
|
// TODO: this doesn't "aggregate". Perhaps we need a different terminology
|
|
17
29
|
// for the base-class and then this implementation can avoid the misleading language.
|
|
30
|
+
/**
|
|
31
|
+
* Handles streaming of spans to the New Relic data collector.
|
|
32
|
+
*/
|
|
18
33
|
class StreamingSpanEventAggregator extends Aggregator {
|
|
19
34
|
constructor(opts, agent) {
|
|
20
35
|
const { metrics, collector, harvester } = agent
|
|
@@ -31,6 +46,11 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
31
46
|
this.isStream = true
|
|
32
47
|
}
|
|
33
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Start streaming spans to the collector.
|
|
51
|
+
*
|
|
52
|
+
* @fires StreamingSpanEventAggregator#started
|
|
53
|
+
*/
|
|
34
54
|
start() {
|
|
35
55
|
if (this.started) {
|
|
36
56
|
return
|
|
@@ -43,6 +63,11 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
43
63
|
this.emit('started')
|
|
44
64
|
}
|
|
45
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Cease streaming of spans to the collector.
|
|
68
|
+
*
|
|
69
|
+
* @fires StreamingSpanEventAggregator#stopped
|
|
70
|
+
*/
|
|
46
71
|
stop() {
|
|
47
72
|
if (!this.started) {
|
|
48
73
|
return
|
|
@@ -60,7 +85,7 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
60
85
|
logger.warnOnce('SEND_WARNING', SEND_WARNING)
|
|
61
86
|
}
|
|
62
87
|
|
|
63
|
-
this.emit(`
|
|
88
|
+
this.emit(`finished_data_send-${this.method}`)
|
|
64
89
|
}
|
|
65
90
|
|
|
66
91
|
/**
|
|
@@ -76,7 +101,7 @@ class StreamingSpanEventAggregator extends Aggregator {
|
|
|
76
101
|
* Attempts to add the given segment to the collection.
|
|
77
102
|
*
|
|
78
103
|
* @param {TraceSegment} segment - The segment to add.
|
|
79
|
-
* @param {string} [parentId
|
|
104
|
+
* @param {string} [parentId] - The GUID of the parent span.
|
|
80
105
|
* @param isRoot
|
|
81
106
|
* @returns {boolean} True if the segment was added, or false if it was discarded.
|
|
82
107
|
*/
|
package/lib/transaction/index.js
CHANGED
|
@@ -70,6 +70,8 @@ const MULTIPLE_INSERT_MESSAGE =
|
|
|
70
70
|
* transaction.
|
|
71
71
|
*
|
|
72
72
|
* @param {object} agent The agent.
|
|
73
|
+
*
|
|
74
|
+
* @fires Agent#transactionStarted
|
|
73
75
|
*/
|
|
74
76
|
function Transaction(agent) {
|
|
75
77
|
if (!agent) {
|
|
@@ -200,6 +202,8 @@ Transaction.prototype.isActive = function isActive() {
|
|
|
200
202
|
* instances of this transaction annotated onto the call stack.
|
|
201
203
|
*
|
|
202
204
|
* @returns {(Transaction|undefined)} this transaction, or undefined
|
|
205
|
+
*
|
|
206
|
+
* @fires Agent#transactionFinished
|
|
203
207
|
*/
|
|
204
208
|
Transaction.prototype.end = function end() {
|
|
205
209
|
if (!this.timer.isActive()) {
|
|
@@ -48,7 +48,7 @@ class TransactionEventAggregator extends EventAggregator {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// TODO: log?
|
|
51
|
-
this.emit(`
|
|
51
|
+
this.emit(`starting_data_send-${this.method}`)
|
|
52
52
|
|
|
53
53
|
logger.debug('Splitting transaction events into multiple payloads')
|
|
54
54
|
|
|
@@ -60,7 +60,7 @@ class TransactionEventAggregator extends EventAggregator {
|
|
|
60
60
|
|
|
61
61
|
this._sendMultiple(eventPayloadPairs, () => {
|
|
62
62
|
// TODO: Log?
|
|
63
|
-
this.emit(`
|
|
63
|
+
this.emit(`finished_data_send-${this.method}`)
|
|
64
64
|
})
|
|
65
65
|
}
|
|
66
66
|
|
package/lib/util/stream-sink.js
CHANGED
|
@@ -8,6 +8,19 @@
|
|
|
8
8
|
const EventEmitter = require('events').EventEmitter
|
|
9
9
|
const util = require('util')
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Triggered when the stream has been terminated.
|
|
13
|
+
*
|
|
14
|
+
* @event StreamSink#close
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Triggered when the stream cannot be written to.
|
|
19
|
+
*
|
|
20
|
+
* @event StreamSink#error
|
|
21
|
+
* @param {Error} error The error that has triggered the event.
|
|
22
|
+
*/
|
|
23
|
+
|
|
11
24
|
/**
|
|
12
25
|
* Pipe a readable stream into this sink that fulfills the Writable Stream
|
|
13
26
|
* contract and the callback will be fired when the stream has been completely
|
|
@@ -30,6 +43,14 @@ function StreamSink(callback) {
|
|
|
30
43
|
}
|
|
31
44
|
util.inherits(StreamSink, EventEmitter)
|
|
32
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Write data to the stream.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} string The data to write.
|
|
50
|
+
* @returns {boolean}
|
|
51
|
+
*
|
|
52
|
+
* @fires StreamSink#error
|
|
53
|
+
*/
|
|
33
54
|
StreamSink.prototype.write = function write(string) {
|
|
34
55
|
if (!this.writable) {
|
|
35
56
|
this.emit('error', new Error('Sink no longer writable!'))
|
|
@@ -49,6 +70,11 @@ StreamSink.prototype.end = function end() {
|
|
|
49
70
|
this.callback(null, this.sink)
|
|
50
71
|
}
|
|
51
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Stop the stream and mark it unusable.
|
|
75
|
+
*
|
|
76
|
+
* @fires StreamSink#close
|
|
77
|
+
*/
|
|
52
78
|
StreamSink.prototype.destroy = function destroy() {
|
|
53
79
|
this.emit('close')
|
|
54
80
|
this.writable = false
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const fs = require('node:fs')
|
|
9
|
-
const http = require('node:http')
|
|
10
9
|
const log = require('../logger').child({ component: 'docker-info' })
|
|
11
10
|
const common = require('./common')
|
|
12
11
|
const NAMES = require('../metrics/names')
|
|
@@ -17,12 +16,17 @@ const CGROUPS_V1_PATH = '/proc/self/cgroup'
|
|
|
17
16
|
const CGROUPS_V2_PATH = '/proc/self/mountinfo'
|
|
18
17
|
const BOOT_ID_PROC_FILE = '/proc/sys/kernel/random/boot_id'
|
|
19
18
|
|
|
20
|
-
module.exports
|
|
21
|
-
|
|
19
|
+
module.exports = {
|
|
20
|
+
clearVendorCache: clearDockerVendorCache,
|
|
21
|
+
getBootId,
|
|
22
|
+
getVendorInfo: fetchDockerVendorInfo
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function clearDockerVendorCache() {
|
|
22
26
|
vendorInfo = null
|
|
23
27
|
}
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
function getBootId(agent, callback, logger = log) {
|
|
26
30
|
if (!/linux/i.test(os.platform())) {
|
|
27
31
|
logger.debug('Platform is not a flavor of linux, omitting boot info')
|
|
28
32
|
return setImmediate(callback, null, null)
|
|
@@ -37,76 +41,8 @@ module.exports.getBootId = function getBootId(agent, callback, logger = log) {
|
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
logger.debug('Container boot id is not available in cgroups info')
|
|
40
|
-
|
|
41
|
-
if (hasAwsContainerApi() === false) {
|
|
42
|
-
// We don't seem to have a recognized location for getting the container
|
|
43
|
-
// identifier.
|
|
44
|
-
logger.debug('Container is not in a recognized ECS container, omitting boot info')
|
|
45
|
-
recordBootIdError(agent)
|
|
46
|
-
return callback(null, null)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
getEcsContainerId({ agent, callback, logger })
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Queries the AWS ECS metadata API to get the boot id.
|
|
55
|
-
*
|
|
56
|
-
* @param {object} params Function parameters.
|
|
57
|
-
* @param {object} params.agent Newrelic agent instance.
|
|
58
|
-
* @param {Function} params.callback Typical error first callback. The second
|
|
59
|
-
* parameter is the boot id as a string.
|
|
60
|
-
* @param {object} [params.logger] Internal logger instance.
|
|
61
|
-
*/
|
|
62
|
-
function getEcsContainerId({ agent, callback, logger }) {
|
|
63
|
-
const ecsApiUrl =
|
|
64
|
-
process.env.ECS_CONTAINER_METADATA_URI_V4 || process.env.ECS_CONTAINER_METADATA_URI
|
|
65
|
-
const req = http.request(ecsApiUrl, (res) => {
|
|
66
|
-
let body = Buffer.alloc(0)
|
|
67
|
-
res.on('data', (chunk) => {
|
|
68
|
-
body = Buffer.concat([body, chunk])
|
|
69
|
-
})
|
|
70
|
-
res.on('end', () => {
|
|
71
|
-
try {
|
|
72
|
-
const json = body.toString('utf8')
|
|
73
|
-
const data = JSON.parse(json)
|
|
74
|
-
if (data.DockerId == null) {
|
|
75
|
-
logger.debug('Failed to find DockerId in response, omitting boot info')
|
|
76
|
-
recordBootIdError(agent)
|
|
77
|
-
return callback(null, null)
|
|
78
|
-
}
|
|
79
|
-
callback(null, data.DockerId)
|
|
80
|
-
} catch (error) {
|
|
81
|
-
logger.debug('Failed to process ECS API response, omitting boot info: ' + error.message)
|
|
82
|
-
recordBootIdError(agent)
|
|
83
|
-
callback(null, null)
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
req.on('error', () => {
|
|
89
|
-
logger.debug('Failed to query ECS endpoint, omitting boot info')
|
|
90
|
-
recordBootIdError(agent)
|
|
91
44
|
callback(null, null)
|
|
92
45
|
})
|
|
93
|
-
|
|
94
|
-
req.end()
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Inspects the running environment to determine if the AWS ECS metadata API
|
|
99
|
-
* is available.
|
|
100
|
-
*
|
|
101
|
-
* @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ec2-metadata.html
|
|
102
|
-
*
|
|
103
|
-
* @returns {boolean}
|
|
104
|
-
*/
|
|
105
|
-
function hasAwsContainerApi() {
|
|
106
|
-
if (process.env.ECS_CONTAINER_METADATA_URI_V4 != null) {
|
|
107
|
-
return true
|
|
108
|
-
}
|
|
109
|
-
return process.env.ECS_CONTAINER_METADATA_URI != null
|
|
110
46
|
}
|
|
111
47
|
|
|
112
48
|
/**
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const http = require('node:http')
|
|
9
|
+
const NAMES = require('../metrics/names')
|
|
10
|
+
|
|
11
|
+
module.exports = function fetchEcsInfo(
|
|
12
|
+
agent,
|
|
13
|
+
callback,
|
|
14
|
+
{
|
|
15
|
+
logger = require('../logger').child({ component: 'ecs-info' }),
|
|
16
|
+
getEcsContainerId = _getEcsContainerId,
|
|
17
|
+
hasAwsContainerApi = _hasAwsContainerApi,
|
|
18
|
+
recordIdError = _recordIdError
|
|
19
|
+
} = {}
|
|
20
|
+
) {
|
|
21
|
+
// Per spec, we do not have a `detect_ecs` key. Since ECS is a service of AWS,
|
|
22
|
+
// we rely on the `detect_aws` setting.
|
|
23
|
+
if (!agent.config.utilization || !agent.config.utilization.detect_aws) {
|
|
24
|
+
return setImmediate(callback, null)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (hasAwsContainerApi() === false) {
|
|
28
|
+
logger.debug('ECS API not available, omitting ECS container id info')
|
|
29
|
+
recordIdError(agent)
|
|
30
|
+
return callback(null, null)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getEcsContainerId({
|
|
34
|
+
agent,
|
|
35
|
+
logger,
|
|
36
|
+
recordIdError,
|
|
37
|
+
callback: (error, dockerId) => {
|
|
38
|
+
if (error) {
|
|
39
|
+
return callback(error, null)
|
|
40
|
+
}
|
|
41
|
+
if (dockerId === null) {
|
|
42
|
+
// Some error happened where we could not find the id. Skipping.
|
|
43
|
+
return callback(null, null)
|
|
44
|
+
}
|
|
45
|
+
return callback(null, { ecsDockerId: dockerId })
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Queries the AWS ECS metadata API to get the boot id.
|
|
52
|
+
*
|
|
53
|
+
* @param {object} params Function parameters.
|
|
54
|
+
* @param {object} params.agent Newrelic agent instance.
|
|
55
|
+
* @param {Function} params.callback Typical error first callback. The second
|
|
56
|
+
* parameter is the boot id as a string.
|
|
57
|
+
* @param {object} params.logger Internal logger instance.
|
|
58
|
+
* @param {function} params.recordIdError Function to record error metric.
|
|
59
|
+
*/
|
|
60
|
+
function _getEcsContainerId({ agent, callback, logger, recordIdError }) {
|
|
61
|
+
const ecsApiUrl =
|
|
62
|
+
process.env.ECS_CONTAINER_METADATA_URI_V4 || process.env.ECS_CONTAINER_METADATA_URI
|
|
63
|
+
const req = http.request(ecsApiUrl, (res) => {
|
|
64
|
+
let body = Buffer.alloc(0)
|
|
65
|
+
res.on('data', (chunk) => {
|
|
66
|
+
body = Buffer.concat([body, chunk])
|
|
67
|
+
})
|
|
68
|
+
res.on('end', () => {
|
|
69
|
+
try {
|
|
70
|
+
const json = body.toString('utf8')
|
|
71
|
+
const data = JSON.parse(json)
|
|
72
|
+
if (data.DockerId == null) {
|
|
73
|
+
logger.debug('Failed to find DockerId in response, omitting boot info')
|
|
74
|
+
recordIdError(agent)
|
|
75
|
+
return callback(null, null)
|
|
76
|
+
}
|
|
77
|
+
callback(null, data.DockerId)
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logger.debug('Failed to process ECS API response, omitting boot info: ' + error.message)
|
|
80
|
+
recordIdError(agent)
|
|
81
|
+
callback(null, null)
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
req.on('error', () => {
|
|
87
|
+
logger.debug('Failed to query ECS endpoint, omitting boot info')
|
|
88
|
+
recordIdError(agent)
|
|
89
|
+
callback(null, null)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
req.end()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Inspects the running environment to determine if the AWS ECS metadata API
|
|
97
|
+
* is available.
|
|
98
|
+
*
|
|
99
|
+
* @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ec2-metadata.html
|
|
100
|
+
*
|
|
101
|
+
* @returns {boolean}
|
|
102
|
+
*/
|
|
103
|
+
function _hasAwsContainerApi() {
|
|
104
|
+
if (process.env.ECS_CONTAINER_METADATA_URI_V4 != null) {
|
|
105
|
+
return true
|
|
106
|
+
}
|
|
107
|
+
return process.env.ECS_CONTAINER_METADATA_URI != null
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function _recordIdError(agent) {
|
|
111
|
+
agent.metrics.getOrCreateMetric(NAMES.UTILIZATION.ECS_CONTAINER_ERROR).incrementCallCount()
|
|
112
|
+
}
|
package/lib/utilization/index.js
CHANGED
|
@@ -9,11 +9,12 @@ const logger = require('../logger').child({ component: 'utilization' })
|
|
|
9
9
|
|
|
10
10
|
const VENDOR_METHODS = {
|
|
11
11
|
aws: require('./aws-info'),
|
|
12
|
-
pcf: require('./pcf-info'),
|
|
13
12
|
azure: require('./azure-info'),
|
|
14
|
-
gcp: require('./gcp-info'),
|
|
15
13
|
docker: require('./docker-info').getVendorInfo,
|
|
16
|
-
|
|
14
|
+
ecs: require('./ecs-info'),
|
|
15
|
+
gcp: require('./gcp-info'),
|
|
16
|
+
kubernetes: require('./kubernetes-info'),
|
|
17
|
+
pcf: require('./pcf-info')
|
|
17
18
|
}
|
|
18
19
|
const VENDOR_NAMES = Object.keys(VENDOR_METHODS)
|
|
19
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.5.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -219,6 +219,7 @@
|
|
|
219
219
|
"@aws-sdk/client-s3": "^3.556.0",
|
|
220
220
|
"@aws-sdk/s3-request-presigner": "^3.556.0",
|
|
221
221
|
"@koa/router": "^12.0.1",
|
|
222
|
+
"@matteo.collina/tspl": "^0.1.1",
|
|
222
223
|
"@newrelic/eslint-config": "^0.3.0",
|
|
223
224
|
"@newrelic/newrelic-oss-cli": "^0.1.2",
|
|
224
225
|
"@newrelic/test-utilities": "^9.1.0",
|
|
@@ -254,7 +255,6 @@
|
|
|
254
255
|
"nock": "11.8.0",
|
|
255
256
|
"proxy": "^2.1.1",
|
|
256
257
|
"proxyquire": "^1.8.0",
|
|
257
|
-
"rfdc": "^1.3.1",
|
|
258
258
|
"rimraf": "^2.6.3",
|
|
259
259
|
"self-cert": "^2.0.0",
|
|
260
260
|
"should": "*",
|