newrelic 12.17.0 → 12.18.1
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 +73 -29
- package/THIRD_PARTY_NOTICES.md +7 -7
- package/lib/config/default.js +15 -1
- package/lib/grpc/connection.js +26 -6
- package/lib/instrumentation/@azure/functions.js +311 -0
- package/lib/instrumentations.js +1 -0
- package/lib/otel/rules.js +30 -7
- package/lib/otel/trace-propagator.js +1 -1
- package/lib/spans/base-span-streamer.js +10 -9
- package/lib/spans/batch-span-streamer.js +28 -25
- package/lib/spans/create-span-event-aggregator.js +2 -1
- package/lib/spans/span-streamer.js +1 -1
- package/lib/transaction/index.js +7 -4
- package/lib/transaction/trace/exclusive-time-calculator.js +4 -1
- package/lib/transaction/tracecontext.js +12 -3
- package/lib/util/logger.js +38 -6
- package/lib/utilization/aws-info.js +6 -3
- package/lib/utilization/azure-info.js +5 -2
- package/lib/utilization/azurefunction-info.js +3 -1
- package/lib/utilization/docker-info.js +12 -9
- package/lib/utilization/ecs-info.js +5 -4
- package/lib/utilization/gcp-info.js +5 -2
- package/lib/utilization/index.js +2 -1
- package/lib/utilization/kubernetes-info.js +4 -2
- package/lib/utilization/pcf-info.js +3 -2
- package/package.json +2 -2
package/NEWS.md
CHANGED
|
@@ -1,32 +1,76 @@
|
|
|
1
|
-
### v12.
|
|
2
|
-
|
|
3
|
-
####
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
### v12.18.1 (2025-04-29)
|
|
2
|
+
|
|
3
|
+
#### Bug fixes
|
|
4
|
+
|
|
5
|
+
* Only add `newrelic` header to outgoing headers if has a value ([#3052](https://github.com/newrelic/node-newrelic/pull/3052)) ([6ef0a90](https://github.com/newrelic/node-newrelic/commit/6ef0a904291fb4efc6d6f111b3ec93aac720c3ad))
|
|
6
|
+
|
|
7
|
+
#### Code refactoring
|
|
8
|
+
|
|
9
|
+
* Added defensive code when calculating exclusive time on a segment where it cannot locate the segment in the transaction trace tree ([#3051](https://github.com/newrelic/node-newrelic/pull/3051)) ([b4aa25e](https://github.com/newrelic/node-newrelic/commit/b4aa25e2df861dab732bb812bffe961c0cc3da36))
|
|
10
|
+
* Updated how otel bridge trace propagator assigns traceparent/tracestate headers ([#3046](https://github.com/newrelic/node-newrelic/pull/3046)) ([6e317b8](https://github.com/newrelic/node-newrelic/commit/6e317b889c68a2e0e69b1d4d2fa9fe2846a0e94f))
|
|
11
|
+
|
|
12
|
+
#### Documentation
|
|
13
|
+
|
|
14
|
+
* Updated compatibility report ([#3054](https://github.com/newrelic/node-newrelic/pull/3054)) ([#3050](https://github.com/newrelic/node-newrelic/pull/3050)) ([#3026](https://github.com/newrelic/node-newrelic/pull/3026))
|
|
15
|
+
|
|
16
|
+
#### Tests
|
|
17
|
+
|
|
18
|
+
* Skipped regressions in pg-native versioned tests ([#3053](https://github.com/newrelic/node-newrelic/pull/3053)) ([6ce3670](https://github.com/newrelic/node-newrelic/commit/6ce36706adc2e17a80b759b51c23807d617ad04f))
|
|
19
|
+
* Updated elasticsearch image for versioned tests ([#3038](https://github.com/newrelic/node-newrelic/pull/3038)) ([3d73f9f](https://github.com/newrelic/node-newrelic/commit/3d73f9faffd45d2d1465210d168822494439c577))
|
|
20
|
+
|
|
21
|
+
### v12.18.0 (2025-04-14)
|
|
22
|
+
|
|
23
|
+
#### Features
|
|
24
|
+
|
|
25
|
+
* Support Azure functions background trigger types ([#3028](https://github.com/newrelic/node-newrelic/pull/3028)) ([3bf17b0](https://github.com/newrelic/node-newrelic/commit/3bf17b03abaa713c1f9ad544c54c24a6374359c2))
|
|
26
|
+
* Support Azure functions HTTP trigger type ([#3021](https://github.com/newrelic/node-newrelic/pull/3021)) ([90d894b](https://github.com/newrelic/node-newrelic/commit/90d894bf1eb4a48f4b7f314ae22eef2cc76c32b9))
|
|
27
|
+
|
|
28
|
+
#### Bug fixes
|
|
29
|
+
|
|
30
|
+
* Updated span streamer to properly retry failed batches and handle flushing batch queue every 5 seconds ([#3033](https://github.com/newrelic/node-newrelic/pull/3033)) ([7db0e7c](https://github.com/newrelic/node-newrelic/commit/7db0e7ca929d54858addd5255b46507f82333045))
|
|
31
|
+
|
|
32
|
+
#### Code refactoring
|
|
33
|
+
|
|
34
|
+
* Update otel bridge rules synthesizer to properly handle consumer kind rules ([#3003](https://github.com/newrelic/node-newrelic/pull/3003)) ([3295dd1](https://github.com/newrelic/node-newrelic/commit/3295dd12bbebb708f3eeca2ad32fbc157a892fec))
|
|
35
|
+
|
|
36
|
+
#### Documentation
|
|
37
|
+
|
|
38
|
+
* Updated compatibility report ([#3020](https://github.com/newrelic/node-newrelic/pull/3020)) ([ce32b67](https://github.com/newrelic/node-newrelic/commit/ce32b6754383b6b1fe95d1d37759810b4caaf34c))
|
|
39
|
+
|
|
40
|
+
#### Miscellaneous chores
|
|
41
|
+
|
|
42
|
+
* Fixed prisma CI issues ([#3031](https://github.com/newrelic/node-newrelic/pull/3031)) ([1349cae](https://github.com/newrelic/node-newrelic/commit/1349cae4d87941e4f55dffc2445c90e73d823bbc))
|
|
43
|
+
* Improved logging within utilization detection ([#3034](https://github.com/newrelic/node-newrelic/pull/3034)) ([b47bd46](https://github.com/newrelic/node-newrelic/commit/b47bd46ad144723ac62192eb9cc474ddd1fce98d))
|
|
44
|
+
|
|
45
|
+
### v12.17.0 (2025-04-02)
|
|
46
|
+
|
|
47
|
+
#### Features
|
|
48
|
+
|
|
49
|
+
* Azure Function utilization ([#3017](https://github.com/newrelic/node-newrelic/pull/3017)) ([80ab93e](https://github.com/newrelic/node-newrelic/commit/80ab93ee5599800a823e3828f9730d5421b460c2))
|
|
50
|
+
* Support honoring W3C `traceparent` sampled flag ([#3009](https://github.com/newrelic/node-newrelic/pull/3009)) ([d903413](https://github.com/newrelic/node-newrelic/commit/d903413a6216dae2cde3e6b6366c3a390d4ed4cd))
|
|
51
|
+
* By default the agent will not honor the `traceparent` sampled flag.
|
|
52
|
+
* To control how sampling works with `traceparent` set the following in config:
|
|
53
|
+
* `distributed_tracing.sampler.remote_parent_sampled`(when the traceparent sampled flag is `01`)
|
|
54
|
+
* `always_on`: the agent will sample spans
|
|
55
|
+
* `always_off`: the agent will not sample spans
|
|
56
|
+
* `default`: the agent will rely on existing priority sampling to make its decisions
|
|
57
|
+
* `distributed_tracing.sampler.remote_parent_not_sampled`(when the traceparent sampled flag is `00`)
|
|
58
|
+
* `always_on`: the agent will sample spans
|
|
59
|
+
* `always_off`: the agent will not sample spans
|
|
60
|
+
* `default`: the agent will rely on existing priority sampling to make its decisions
|
|
61
|
+
|
|
62
|
+
#### Code refactoring
|
|
63
|
+
|
|
64
|
+
* Updated otel bridge to centralize mapping rules for a given span attribute to accomondate semantic convention spec updates ([#3010](https://github.com/newrelic/node-newrelic/pull/3010)) ([c20c36b](https://github.com/newrelic/node-newrelic/commit/c20c36bbe0f63ab18fbbe85ad4bfaa3b80f1475d))
|
|
65
|
+
|
|
66
|
+
#### Documentation
|
|
67
|
+
|
|
68
|
+
* Updated compatibility report ([#3013](https://github.com/newrelic/node-newrelic/pull/3013)) ([8fab715](https://github.com/newrelic/node-newrelic/commit/8fab715581ccc5da7118884a0080557891329daa))
|
|
69
|
+
|
|
70
|
+
#### Tests
|
|
71
|
+
|
|
72
|
+
* Pinned `openai@4.90.0` to work with `@langchain/openai` ([#3019](https://github.com/newrelic/node-newrelic/pull/3019)) ([eaa3db0](https://github.com/newrelic/node-newrelic/commit/eaa3db0a556a19c44a05926dc339ea7bcbc9cebd))
|
|
73
|
+
|
|
30
74
|
### v12.16.1 (2025-03-24)
|
|
31
75
|
|
|
32
76
|
#### Features
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -91,7 +91,7 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
91
91
|
|
|
92
92
|
### @grpc/grpc-js
|
|
93
93
|
|
|
94
|
-
This product includes source derived from [@grpc/grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) ([v1.
|
|
94
|
+
This product includes source derived from [@grpc/grpc-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) ([v1.13.2](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js/tree/v1.13.2)), distributed under the [Apache-2.0 License](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js/blob/v1.13.2/LICENSE):
|
|
95
95
|
|
|
96
96
|
```
|
|
97
97
|
Apache License
|
|
@@ -509,7 +509,7 @@ This product includes source derived from [@grpc/proto-loader](https://github.co
|
|
|
509
509
|
|
|
510
510
|
### @newrelic/security-agent
|
|
511
511
|
|
|
512
|
-
This product includes source derived from [@newrelic/security-agent](https://github.com/newrelic/csec-node-agent) ([v2.
|
|
512
|
+
This product includes source derived from [@newrelic/security-agent](https://github.com/newrelic/csec-node-agent) ([v2.4.0](https://github.com/newrelic/csec-node-agent/tree/v2.4.0)), distributed under the [UNKNOWN License](https://github.com/newrelic/csec-node-agent/blob/v2.4.0/LICENSE):
|
|
513
513
|
|
|
514
514
|
```
|
|
515
515
|
## New Relic Software License v1.0
|
|
@@ -1271,7 +1271,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
1271
1271
|
|
|
1272
1272
|
### import-in-the-middle
|
|
1273
1273
|
|
|
1274
|
-
This product includes source derived from [import-in-the-middle](https://github.com/nodejs/import-in-the-middle) ([v1.13.
|
|
1274
|
+
This product includes source derived from [import-in-the-middle](https://github.com/nodejs/import-in-the-middle) ([v1.13.1](https://github.com/nodejs/import-in-the-middle/tree/v1.13.1)), distributed under the [Apache-2.0 License](https://github.com/nodejs/import-in-the-middle/blob/v1.13.1/LICENSE):
|
|
1275
1275
|
|
|
1276
1276
|
```
|
|
1277
1277
|
Apache License
|
|
@@ -1615,7 +1615,7 @@ IN THE SOFTWARE.
|
|
|
1615
1615
|
|
|
1616
1616
|
### require-in-the-middle
|
|
1617
1617
|
|
|
1618
|
-
This product includes source derived from [require-in-the-middle](https://github.com/elastic/require-in-the-middle) ([v7.
|
|
1618
|
+
This product includes source derived from [require-in-the-middle](https://github.com/elastic/require-in-the-middle) ([v7.5.0](https://github.com/elastic/require-in-the-middle/tree/v7.5.0)), distributed under the [MIT License](https://github.com/elastic/require-in-the-middle/blob/v7.5.0/LICENSE):
|
|
1619
1619
|
|
|
1620
1620
|
```
|
|
1621
1621
|
The MIT License (MIT)
|
|
@@ -1701,7 +1701,7 @@ SOFTWARE.
|
|
|
1701
1701
|
|
|
1702
1702
|
### @aws-sdk/client-s3
|
|
1703
1703
|
|
|
1704
|
-
This product includes source derived from [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3) ([v3.
|
|
1704
|
+
This product includes source derived from [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3) ([v3.726.1](https://github.com/aws/aws-sdk-js-v3/tree/v3.726.1)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.726.1/LICENSE):
|
|
1705
1705
|
|
|
1706
1706
|
```
|
|
1707
1707
|
Apache License
|
|
@@ -1910,7 +1910,7 @@ This product includes source derived from [@aws-sdk/client-s3](https://github.co
|
|
|
1910
1910
|
|
|
1911
1911
|
### @aws-sdk/s3-request-presigner
|
|
1912
1912
|
|
|
1913
|
-
This product includes source derived from [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3) ([v3.
|
|
1913
|
+
This product includes source derived from [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3) ([v3.726.1](https://github.com/aws/aws-sdk-js-v3/tree/v3.726.1)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.726.1/LICENSE):
|
|
1914
1914
|
|
|
1915
1915
|
```
|
|
1916
1916
|
Apache License
|
|
@@ -3770,7 +3770,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
3770
3770
|
|
|
3771
3771
|
### eslint
|
|
3772
3772
|
|
|
3773
|
-
This product includes source derived from [eslint](https://github.com/eslint/eslint) ([v9.
|
|
3773
|
+
This product includes source derived from [eslint](https://github.com/eslint/eslint) ([v9.18.0](https://github.com/eslint/eslint/tree/v9.18.0)), distributed under the [MIT License](https://github.com/eslint/eslint/blob/v9.18.0/LICENSE):
|
|
3774
3774
|
|
|
3775
3775
|
```
|
|
3776
3776
|
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
package/lib/config/default.js
CHANGED
|
@@ -1197,7 +1197,14 @@ defaultConfig.definition = () => ({
|
|
|
1197
1197
|
port: {
|
|
1198
1198
|
formatter: int,
|
|
1199
1199
|
default: 443
|
|
1200
|
-
}
|
|
1200
|
+
},
|
|
1201
|
+
/**
|
|
1202
|
+
* For testing only. This allows the connection to an insecure gRPC server.
|
|
1203
|
+
*/
|
|
1204
|
+
insecure: {
|
|
1205
|
+
formatter: boolean,
|
|
1206
|
+
default: false
|
|
1207
|
+
},
|
|
1201
1208
|
},
|
|
1202
1209
|
span_events: {
|
|
1203
1210
|
/**
|
|
@@ -1206,6 +1213,13 @@ defaultConfig.definition = () => ({
|
|
|
1206
1213
|
queue_size: {
|
|
1207
1214
|
formatter: int,
|
|
1208
1215
|
default: 10000
|
|
1216
|
+
},
|
|
1217
|
+
/**
|
|
1218
|
+
* Size of batches to post to 8T server
|
|
1219
|
+
*/
|
|
1220
|
+
batch_size: {
|
|
1221
|
+
formatter: int,
|
|
1222
|
+
default: 750
|
|
1209
1223
|
}
|
|
1210
1224
|
},
|
|
1211
1225
|
batching: {
|
package/lib/grpc/connection.js
CHANGED
|
@@ -62,6 +62,7 @@ class GrpcConnection extends EventEmitter {
|
|
|
62
62
|
|
|
63
63
|
const traceObserverConfig = infiniteTracingConfig.trace_observer
|
|
64
64
|
this._endpoint = this.getTraceObserverEndpoint(traceObserverConfig)
|
|
65
|
+
this._insecureConnection = traceObserverConfig.insecure
|
|
65
66
|
|
|
66
67
|
this._client = null
|
|
67
68
|
this.stream = null
|
|
@@ -202,11 +203,13 @@ class GrpcConnection extends EventEmitter {
|
|
|
202
203
|
|
|
203
204
|
_disconnect() {
|
|
204
205
|
logger.trace('Disconnecting from gRPC endpoint.')
|
|
206
|
+
this._setState(connectionStates.disconnected)
|
|
205
207
|
|
|
206
208
|
if (this.stream) {
|
|
207
209
|
this.stream.removeAllListeners()
|
|
208
210
|
|
|
209
211
|
const oldStream = this.stream
|
|
212
|
+
|
|
210
213
|
this.stream.on('status', function endStreamStatusHandler(grpcStatus) {
|
|
211
214
|
logger.trace('End stream status received [%s]: %s', grpcStatus.code, grpcStatus.details)
|
|
212
215
|
|
|
@@ -228,8 +231,6 @@ class GrpcConnection extends EventEmitter {
|
|
|
228
231
|
|
|
229
232
|
this.stream = null
|
|
230
233
|
}
|
|
231
|
-
|
|
232
|
-
this._setState(connectionStates.disconnected)
|
|
233
234
|
}
|
|
234
235
|
|
|
235
236
|
/**
|
|
@@ -374,12 +375,10 @@ class GrpcConnection extends EventEmitter {
|
|
|
374
375
|
|
|
375
376
|
const traceApi = protoDescriptor.com.newrelic.trace.v1
|
|
376
377
|
|
|
377
|
-
const credentials = this._generateCredentials(grpc)
|
|
378
|
-
|
|
379
|
-
// If you want to use mock server use insecure creds
|
|
380
|
-
// const credentials = grpc.credentials.createInsecure()
|
|
378
|
+
const credentials = this._insecureConnection ? grpc.credentials.createInsecure() : this._generateCredentials(grpc)
|
|
381
379
|
|
|
382
380
|
const opts = {}
|
|
381
|
+
|
|
383
382
|
if (this._compression) {
|
|
384
383
|
// 2 = gzip compression
|
|
385
384
|
// see: https://github.com/grpc/grpc-node/blob/master/packages/grpc-js/src/compression-algorithms.ts#L21
|
|
@@ -393,6 +392,27 @@ class GrpcConnection extends EventEmitter {
|
|
|
393
392
|
.incrementCallCount()
|
|
394
393
|
}
|
|
395
394
|
|
|
395
|
+
// this defines retries of writes to stream if it fails with `UNAVAILABLE` or `INTERNAL`
|
|
396
|
+
const serviceConfig = {
|
|
397
|
+
methodConfig: [
|
|
398
|
+
{
|
|
399
|
+
name: [
|
|
400
|
+
{
|
|
401
|
+
service: 'com.newrelic.trace.v1.IngestService'
|
|
402
|
+
}
|
|
403
|
+
],
|
|
404
|
+
retryPolicy: {
|
|
405
|
+
maxAttempts: 10,
|
|
406
|
+
initialBackoff: '0.1s',
|
|
407
|
+
maxBackoff: '1s',
|
|
408
|
+
backoffMultiplier: 2,
|
|
409
|
+
retryableStatusCodes: ['UNAVAILABLE', 'INTERNAL']
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
]
|
|
413
|
+
}
|
|
414
|
+
opts['grpc.service_config'] = JSON.stringify(serviceConfig)
|
|
415
|
+
|
|
396
416
|
return new traceApi.IngestService(endpoint, credentials, opts)
|
|
397
417
|
}
|
|
398
418
|
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const defaultLogger = require('../../logger').child({ component: 'azure-functions' })
|
|
9
|
+
const urltils = require('../../util/urltils')
|
|
10
|
+
const headerProcessing = require('../../header-processing')
|
|
11
|
+
const synthetics = require('../../synthetics')
|
|
12
|
+
|
|
13
|
+
const backgroundRecorder = require('../../metrics/recorders/other.js')
|
|
14
|
+
const recordWeb = require('../../metrics/recorders/http')
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
DESTINATIONS: DESTS,
|
|
18
|
+
TYPES
|
|
19
|
+
} = require('../../transaction/index.js')
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
WEBSITE_OWNER_NAME,
|
|
23
|
+
WEBSITE_RESOURCE_GROUP,
|
|
24
|
+
WEBSITE_SITE_NAME
|
|
25
|
+
} = process.env
|
|
26
|
+
const SUBSCRIPTION_ID = WEBSITE_OWNER_NAME?.split('+').shift()
|
|
27
|
+
const RESOURCE_GROUP_NAME = WEBSITE_RESOURCE_GROUP ?? WEBSITE_OWNER_NAME?.split('+').pop().split('-Linux').shift()
|
|
28
|
+
const AZURE_FUNCTION_APP_NAME = WEBSITE_SITE_NAME
|
|
29
|
+
|
|
30
|
+
let coldStart = true
|
|
31
|
+
let _agent
|
|
32
|
+
let _logger
|
|
33
|
+
|
|
34
|
+
module.exports = function initialize(agent, azureFunctions, _moduleName, shim, { logger = defaultLogger } = {}) {
|
|
35
|
+
_agent = agent
|
|
36
|
+
_logger = logger
|
|
37
|
+
if (!SUBSCRIPTION_ID || !RESOURCE_GROUP_NAME || !AZURE_FUNCTION_APP_NAME) {
|
|
38
|
+
logger.warn(
|
|
39
|
+
{
|
|
40
|
+
data: {
|
|
41
|
+
expectedVars: ['WEBSITE_OWNER_NAME', 'WEBSITE_RESOURCE_GROUP', 'WEBSITE_SITE_NAME'],
|
|
42
|
+
found: { WEBSITE_OWNER_NAME, WEBSITE_RESOURCE_GROUP, WEBSITE_SITE_NAME }
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
'could not initialize azure functions instrumentation due to missing environment variables'
|
|
46
|
+
)
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const httpMethods = ['http', 'get', 'put', 'post', 'patch', 'deleteRequest']
|
|
51
|
+
shim.wrap(azureFunctions.app, httpMethods, wrapAzureHttpMethods)
|
|
52
|
+
|
|
53
|
+
const backgroundMethods = [
|
|
54
|
+
'cosmosDB',
|
|
55
|
+
'eventGrid',
|
|
56
|
+
'eventHub',
|
|
57
|
+
'mySql',
|
|
58
|
+
'serviceBusQueue',
|
|
59
|
+
'serviceBusTopic',
|
|
60
|
+
'sql',
|
|
61
|
+
'storageBlob',
|
|
62
|
+
'storageQueue',
|
|
63
|
+
'timer',
|
|
64
|
+
'warmup',
|
|
65
|
+
'webPubSub'
|
|
66
|
+
]
|
|
67
|
+
shim.wrap(azureFunctions.app, backgroundMethods, wrapAzureBackgroundMethods)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function wrapAzureHttpMethods(shim, appMethod) {
|
|
71
|
+
return async function wrappedAzureHttpMethod(...args) {
|
|
72
|
+
// If the app doesn't need an options object, the user can pass the
|
|
73
|
+
// handler function as the second argument
|
|
74
|
+
// (e.g. `app.get('name', handler)`).
|
|
75
|
+
// See https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=javascript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#registering-a-function
|
|
76
|
+
let handler
|
|
77
|
+
if (typeof args[1] === 'function') {
|
|
78
|
+
handler = args[1]
|
|
79
|
+
args[1] = { handler }
|
|
80
|
+
} else {
|
|
81
|
+
handler = args[1].handler
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const tracer = shim.tracer
|
|
85
|
+
args[1].handler = tracer.transactionProxy(async function wrappedHandler(...args) {
|
|
86
|
+
const [request, context] = args
|
|
87
|
+
const ctx = tracer.getContext()
|
|
88
|
+
const tx = tracer.getTransaction()
|
|
89
|
+
|
|
90
|
+
// Set the transaction name according to our spec (category + function name).
|
|
91
|
+
tx.setPartialName(`AzureFunction/${context.functionName}`)
|
|
92
|
+
|
|
93
|
+
const url = new URL(request.url)
|
|
94
|
+
const segment = tracer.createSegment({
|
|
95
|
+
name: request.url,
|
|
96
|
+
recorder: recordWeb,
|
|
97
|
+
parent: ctx.segment,
|
|
98
|
+
transaction: tx
|
|
99
|
+
})
|
|
100
|
+
segment.start()
|
|
101
|
+
|
|
102
|
+
const transport = url.protocol === 'https:' ? 'HTTPS' : 'HTTP'
|
|
103
|
+
tx.type = TYPES.WEB
|
|
104
|
+
tx.baseSegment = segment
|
|
105
|
+
tx.parsedUrl = url
|
|
106
|
+
tx.url = urltils.obfuscatePath(_agent.config, url.pathname)
|
|
107
|
+
tx.verb = request.method
|
|
108
|
+
if (url.port === '') {
|
|
109
|
+
tx.port = transport === 'HTTPS' ? '443' : '80'
|
|
110
|
+
} else {
|
|
111
|
+
tx.port = url.port
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
tx.trace.attributes.addAttribute(
|
|
115
|
+
DESTS.TRANS_EVENT | DESTS.ERROR_EVENT,
|
|
116
|
+
'request.uri',
|
|
117
|
+
tx.url
|
|
118
|
+
)
|
|
119
|
+
segment.addSpanAttribute('request.uri', tx.url)
|
|
120
|
+
if (request.method != null) {
|
|
121
|
+
segment.addSpanAttribute('request.method', request.method)
|
|
122
|
+
}
|
|
123
|
+
addAttributes({ transaction: tx, functionContext: context })
|
|
124
|
+
|
|
125
|
+
const queueTimeStamp = headerProcessing.getQueueTime(_logger, request.headers)
|
|
126
|
+
if (queueTimeStamp) {
|
|
127
|
+
tx.queueTime = Date.now() - queueTimeStamp
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
synthetics.assignHeadersToTransaction(_agent.config, tx, request.headers)
|
|
131
|
+
if (_agent.config.distributed_tracing.enabled === true) {
|
|
132
|
+
tx.acceptDistributedTraceHeaders(transport, request.headers)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const newContext = ctx.enterSegment({ segment })
|
|
136
|
+
const boundHandler = tracer.bindFunction(handler, newContext)
|
|
137
|
+
|
|
138
|
+
const result = await boundHandler(...args)
|
|
139
|
+
// Responses should have a shape as described at:
|
|
140
|
+
// https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=javascript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#http-response
|
|
141
|
+
if (result.status) {
|
|
142
|
+
tx.trace.attributes.addAttribute(
|
|
143
|
+
DESTS.TRANS_COMMON,
|
|
144
|
+
'http.statusCode',
|
|
145
|
+
result.status
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (coldStart === true) {
|
|
150
|
+
tx.trace.attributes.addAttribute(DESTS.TRANS_COMMON, 'faas.coldStart', true)
|
|
151
|
+
coldStart = false
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
tx.end()
|
|
155
|
+
return result
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
await appMethod(...args)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function wrapAzureBackgroundMethods(shim, appMethod) {
|
|
163
|
+
return async function wrappedAzureBackgroundMethod(...args) {
|
|
164
|
+
let handler
|
|
165
|
+
if (typeof args[1] === 'function') {
|
|
166
|
+
handler = args[1]
|
|
167
|
+
args[1] = { handler }
|
|
168
|
+
} else {
|
|
169
|
+
handler = args[1].handler
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const tracer = shim.tracer
|
|
173
|
+
args[1].handler = tracer.transactionProxy(async function wrappedHandler(...args) {
|
|
174
|
+
const [, context] = args
|
|
175
|
+
const ctx = tracer.getContext()
|
|
176
|
+
const tx = tracer.getTransaction()
|
|
177
|
+
|
|
178
|
+
tx.setPartialName(`AzureFunction/${context.functionName}`)
|
|
179
|
+
|
|
180
|
+
const segment = tracer.createSegment({
|
|
181
|
+
name: `${appMethod}-trigger`,
|
|
182
|
+
recorder: backgroundRecorder,
|
|
183
|
+
parent: ctx.segment,
|
|
184
|
+
transaction: tx
|
|
185
|
+
})
|
|
186
|
+
segment.start()
|
|
187
|
+
|
|
188
|
+
tx.type = TYPES.BG
|
|
189
|
+
tx.baseSegment = segment
|
|
190
|
+
addAttributes({ transaction: tx, functionContext: context })
|
|
191
|
+
|
|
192
|
+
const newContext = ctx.enterSegment({ segment })
|
|
193
|
+
const boundHandler = tracer.bindFunction(handler, newContext)
|
|
194
|
+
|
|
195
|
+
const result = await boundHandler(...args)
|
|
196
|
+
if (coldStart === true) {
|
|
197
|
+
tx.trace.attributes.addAttribute(DESTS.TRANS_COMMON, 'faas.coldStart', true)
|
|
198
|
+
coldStart = false
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
tx.end()
|
|
202
|
+
return result
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
await appMethod(...args)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Add required New Relic attributes to the transaction.
|
|
211
|
+
*
|
|
212
|
+
* @param {object} params Function parameters.
|
|
213
|
+
* @param {Transaction} params.transaction The transaction to update.
|
|
214
|
+
* @param {object} params.functionContext The function invocation context
|
|
215
|
+
* provided by the Azure functions runtime.
|
|
216
|
+
*/
|
|
217
|
+
function addAttributes({ transaction, functionContext }) {
|
|
218
|
+
transaction.trace.attributes.addAttribute(
|
|
219
|
+
DESTS.TRANS_COMMON,
|
|
220
|
+
'faas.invocation_id',
|
|
221
|
+
functionContext.invocationId ?? 'unknown'
|
|
222
|
+
)
|
|
223
|
+
transaction.trace.attributes.addAttribute(
|
|
224
|
+
DESTS.TRANS_COMMON,
|
|
225
|
+
'faas.name',
|
|
226
|
+
functionContext.functionName ?? 'unknown'
|
|
227
|
+
)
|
|
228
|
+
transaction.trace.attributes.addAttribute(
|
|
229
|
+
DESTS.TRANS_COMMON,
|
|
230
|
+
'faas.trigger',
|
|
231
|
+
mapTriggerType({ functionContext })
|
|
232
|
+
)
|
|
233
|
+
transaction.trace.attributes.addAttribute(
|
|
234
|
+
DESTS.TRANS_COMMON,
|
|
235
|
+
'cloud.resource_id',
|
|
236
|
+
buildCloudResourceId({ functionContext })
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Inspects the provided function invocation context and returns a recognized
|
|
242
|
+
* trigger type suitable for sending to the collector as `faas.trigger`.
|
|
243
|
+
*
|
|
244
|
+
* @param {object} params Function parameters
|
|
245
|
+
* @param {object} params.functionContext The function context as provided by
|
|
246
|
+
* the Azure functions runtime.
|
|
247
|
+
*
|
|
248
|
+
* @returns {string} A string appropriate for New Relic.
|
|
249
|
+
*/
|
|
250
|
+
function mapTriggerType({ functionContext }) {
|
|
251
|
+
const input = functionContext.options?.trigger?.type
|
|
252
|
+
|
|
253
|
+
// Input types are found at:
|
|
254
|
+
// https://github.com/Azure/azure-functions-nodejs-library/blob/138c021/src/trigger.ts
|
|
255
|
+
// https://learn.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings?tabs=isolated-process%2Cnode-v4%2Cpython-v2&pivots=programming-language-javascript#supported-bindings
|
|
256
|
+
switch (input) {
|
|
257
|
+
case 'httpTrigger': {
|
|
258
|
+
return 'http'
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
case 'timerTrigger': {
|
|
262
|
+
return 'timer'
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
case 'blobTrigger':
|
|
266
|
+
case 'cosmosDBTrigger':
|
|
267
|
+
case 'daprBindingTrigger':
|
|
268
|
+
case 'mysqlTrigger':
|
|
269
|
+
case 'queueTrigger':
|
|
270
|
+
case 'sqlTrigger': {
|
|
271
|
+
return 'datasource'
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
case 'daprTopicTrigger':
|
|
275
|
+
case 'eventGridTrigger':
|
|
276
|
+
case 'eventHubTrigger':
|
|
277
|
+
case 'kafkaTrigger':
|
|
278
|
+
case 'rabbitMQTrigger':
|
|
279
|
+
case 'redisListTrigger':
|
|
280
|
+
case 'redisPubSubTrigger':
|
|
281
|
+
case 'redisStreamTrigger':
|
|
282
|
+
case 'serviceBusTrigger':
|
|
283
|
+
case 'signalRTrigger':
|
|
284
|
+
case 'webPubSubTrigger': {
|
|
285
|
+
return 'pubsub'
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
default: {
|
|
289
|
+
return 'other'
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function buildCloudResourceId({ functionContext }) {
|
|
295
|
+
return [
|
|
296
|
+
'/subscriptions/',
|
|
297
|
+
SUBSCRIPTION_ID,
|
|
298
|
+
'/resourceGroups/',
|
|
299
|
+
RESOURCE_GROUP_NAME,
|
|
300
|
+
'/providers/Microsoft.Web/sites/',
|
|
301
|
+
AZURE_FUNCTION_APP_NAME,
|
|
302
|
+
'/functions/',
|
|
303
|
+
functionContext.functionName
|
|
304
|
+
].join('')
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
module.exports.internals = {
|
|
308
|
+
addAttributes,
|
|
309
|
+
mapTriggerType,
|
|
310
|
+
buildCloudResourceId
|
|
311
|
+
}
|
package/lib/instrumentations.js
CHANGED
|
@@ -10,6 +10,7 @@ const InstrumentationDescriptor = require('./instrumentation-descriptor')
|
|
|
10
10
|
// Return a new copy of this array every time we're called
|
|
11
11
|
module.exports = function instrumentations() {
|
|
12
12
|
return {
|
|
13
|
+
'@azure/functions': { type: InstrumentationDescriptor.TYPE_GENERIC },
|
|
13
14
|
'@elastic/elasticsearch': { type: InstrumentationDescriptor.TYPE_DATASTORE },
|
|
14
15
|
'@opensearch-project/opensearch': { type: InstrumentationDescriptor.TYPE_DATASTORE },
|
|
15
16
|
'@grpc/grpc-js': { module: './instrumentation/grpc-js' },
|