newrelic 12.1.1 → 12.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.
- package/NEWS.md +50 -0
- package/README.md +0 -1
- package/THIRD_PARTY_NOTICES.md +42 -42
- package/api.js +49 -0
- package/lib/instrumentation/aws-sdk/v3/bedrock.js +7 -1
- package/lib/instrumentation/express.js +9 -65
- package/lib/instrumentation/koa/instrumentation.js +2 -20
- package/lib/instrumentation/langchain/common.js +7 -1
- package/lib/instrumentation/langchain/nr-hooks.js +9 -1
- package/lib/instrumentation/openai.js +7 -1
- package/lib/serverless/api-gateway.js +38 -29
- package/lib/shimmer.js +1 -1
- package/lib/util/llm-utils.js +34 -0
- package/package.json +6 -6
package/NEWS.md
CHANGED
|
@@ -1,3 +1,53 @@
|
|
|
1
|
+
### v12.3.0 (2024-08-27)
|
|
2
|
+
|
|
3
|
+
#### Features
|
|
4
|
+
|
|
5
|
+
* Added new API method `withLlmCustomAttributes` to run a function in a LLM context ([#2437](https://github.com/newrelic/node-newrelic/pull/2437)) ([57e6be9](https://github.com/newrelic/node-newrelic/commit/57e6be9f4717fde3caada0e3ca3680959180f928))
|
|
6
|
+
* The context will be used to assign custom attributes to every LLM event produced within the function
|
|
7
|
+
|
|
8
|
+
#### Bug fixes
|
|
9
|
+
|
|
10
|
+
* Improved AWS Lambda event detection ([#2498](https://github.com/newrelic/node-newrelic/pull/2498)) ([5e8b260](https://github.com/newrelic/node-newrelic/commit/5e8b2608d9914e2a4282f7c9c42ff17dfa9f793e))
|
|
11
|
+
|
|
12
|
+
#### Documentation
|
|
13
|
+
|
|
14
|
+
* Updated compatibility report ([#2493](https://github.com/newrelic/node-newrelic/pull/2493)) ([0448927](https://github.com/newrelic/node-newrelic/commit/0448927a49254b5b3c7ed9ff072cec24449fc558))
|
|
15
|
+
|
|
16
|
+
#### Miscellaneous chores
|
|
17
|
+
* Fixed linting scripts ([#2497](https://github.com/newrelic/node-newrelic/pull/2497)) ([c395779](https://github.com/newrelic/node-newrelic/commit/c395779f499cca0ec7f915342c23b2d2381b0163))
|
|
18
|
+
* Removed examples/shim ([#2484](https://github.com/newrelic/node-newrelic/pull/2484)) ([40d1f5c](https://github.com/newrelic/node-newrelic/commit/40d1f5ccc50d49805fc68946806fc9f74179673b))
|
|
19
|
+
* Updated test-utils dependency and added matrix-count only ([#2494](https://github.com/newrelic/node-newrelic/pull/2494)) ([5e04c76](https://github.com/newrelic/node-newrelic/commit/5e04c76600b8e6b7bfe331c2bec1b6cfa05ab922))
|
|
20
|
+
|
|
21
|
+
#### Tests
|
|
22
|
+
|
|
23
|
+
* Converted the api unit tests to `node:test` ([#2516](https://github.com/newrelic/node-newrelic/pull/2516)) ([ab91576](https://github.com/newrelic/node-newrelic/commit/ab91576fa949161f902b1604752a7fc38e7f2a74))
|
|
24
|
+
* Converted context-manager unit tests to `node:test` ([#2508](https://github.com/newrelic/node-newrelic/pull/2508)) ([9363eb0](https://github.com/newrelic/node-newrelic/commit/9363eb08ce8a13e67f94e5378ca95f32a562d504))
|
|
25
|
+
|
|
26
|
+
#### Continuous integration
|
|
27
|
+
|
|
28
|
+
* Updated codecov action sha to post coverage from forks. Added flag to fail ci if it fails to upload report ([#2490](https://github.com/newrelic/node-newrelic/pull/2490)) ([12fbe56](https://github.com/newrelic/node-newrelic/commit/12fbe56ca2581b3dd5cc5e2c1eceade46a8d191d))
|
|
29
|
+
|
|
30
|
+
### v12.2.0 (2024-08-19)
|
|
31
|
+
|
|
32
|
+
#### Features
|
|
33
|
+
|
|
34
|
+
* Added instrumentation support for Express 5 beta ([#2476](https://github.com/newrelic/node-newrelic/pull/2476)) ([06a4c2f](https://github.com/newrelic/node-newrelic/commit/06a4c2f9d62f7313fd246b4eed7f9f04f8b6345b))
|
|
35
|
+
* This will be experimental until `express@5.0.0` is generally available
|
|
36
|
+
|
|
37
|
+
#### Bug fixes
|
|
38
|
+
|
|
39
|
+
* Updated `koa` instrumentation to properly get the matched route name and to handle changes in `@koa/router@13.0.0` ([#2486](https://github.com/newrelic/node-newrelic/pull/2486)) ([0c2ee2f](https://github.com/newrelic/node-newrelic/commit/0c2ee2fd1698972de35a0ad2685e626a074125ed))
|
|
40
|
+
|
|
41
|
+
#### Documentation
|
|
42
|
+
|
|
43
|
+
* Removed reference to `@newrelic/next` in README ([#2479](https://github.com/newrelic/node-newrelic/pull/2479)) ([8740539](https://github.com/newrelic/node-newrelic/commit/8740539c4004e421e5f26d0c92216bcffb93c9cc))
|
|
44
|
+
* Updated compatibility report ([#2487](https://github.com/newrelic/node-newrelic/pull/2487)) ([c0a5e64](https://github.com/newrelic/node-newrelic/commit/c0a5e646773c365897a908daf034881703dbd1df))
|
|
45
|
+
|
|
46
|
+
#### Miscellaneous chores
|
|
47
|
+
|
|
48
|
+
* Reverted to upstream `require-in-the-middle` ([#2473](https://github.com/newrelic/node-newrelic/pull/2473)) ([9bbc41c](https://github.com/newrelic/node-newrelic/commit/9bbc41c5be479af56d5aa0c87291d2fec607e9e4))
|
|
49
|
+
* Updated aggregators unit tests to node:test ([#2481](https://github.com/newrelic/node-newrelic/pull/2481)) ([fd2d76f](https://github.com/newrelic/node-newrelic/commit/fd2d76fb2f6e8debc165700f932d57a02c3d3956))
|
|
50
|
+
|
|
1
51
|
### v12.1.1 (2024-08-15)
|
|
2
52
|
|
|
3
53
|
#### Bug fixes
|
package/README.md
CHANGED
|
@@ -152,7 +152,6 @@ For more information on getting started, [check the Node.js docs](https://docs.n
|
|
|
152
152
|
There are modules that can be installed and configured to accompany the Node.js agent:
|
|
153
153
|
|
|
154
154
|
* [@newrelic/apollo-server-plugin](https://github.com/newrelic/newrelic-node-apollo-server-plugin): New Relic's official Apollo Server plugin for use with the Node.js agent.
|
|
155
|
-
* [@newrelic/next](https://github.com/newrelic/newrelic-node-nextjs): Provides instrumentation for the [Next.js](https://github.com/vercel/next.js/) npm package.
|
|
156
155
|
|
|
157
156
|
There are modules included within the Node.js agent to add more instrumentation for 3rd party modules:
|
|
158
157
|
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -16,7 +16,6 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
16
16
|
|
|
17
17
|
* [@grpc/grpc-js](#grpcgrpc-js)
|
|
18
18
|
* [@grpc/proto-loader](#grpcproto-loader)
|
|
19
|
-
* [@newrelic/ritm](#newrelicritm)
|
|
20
19
|
* [@newrelic/security-agent](#newrelicsecurity-agent)
|
|
21
20
|
* [@tyriar/fibonacci-heap](#tyriarfibonacci-heap)
|
|
22
21
|
* [concat-stream](#concat-stream)
|
|
@@ -26,6 +25,7 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
|
|
|
26
25
|
* [json-stringify-safe](#json-stringify-safe)
|
|
27
26
|
* [module-details-from-path](#module-details-from-path)
|
|
28
27
|
* [readable-stream](#readable-stream)
|
|
28
|
+
* [require-in-the-middle](#require-in-the-middle)
|
|
29
29
|
* [semver](#semver)
|
|
30
30
|
* [winston-transport](#winston-transport)
|
|
31
31
|
|
|
@@ -509,39 +509,9 @@ This product includes source derived from [@grpc/proto-loader](https://github.co
|
|
|
509
509
|
|
|
510
510
|
```
|
|
511
511
|
|
|
512
|
-
### @newrelic/ritm
|
|
513
|
-
|
|
514
|
-
This product includes source derived from [@newrelic/ritm](https://github.com/newrelic-forks/require-in-the-middle) ([v7.2.0](https://github.com/newrelic-forks/require-in-the-middle/tree/v7.2.0)), distributed under the [MIT License](https://github.com/newrelic-forks/require-in-the-middle/blob/v7.2.0/LICENSE):
|
|
515
|
-
|
|
516
|
-
```
|
|
517
|
-
The MIT License (MIT)
|
|
518
|
-
|
|
519
|
-
Copyright (c) 2016-2019, Thomas Watson Steen
|
|
520
|
-
Copyright (c) 2019-2023, Elasticsearch B.V.
|
|
521
|
-
|
|
522
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
523
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
524
|
-
in the Software without restriction, including without limitation the rights
|
|
525
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
526
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
527
|
-
furnished to do so, subject to the following conditions:
|
|
528
|
-
|
|
529
|
-
The above copyright notice and this permission notice shall be included in all
|
|
530
|
-
copies or substantial portions of the Software.
|
|
531
|
-
|
|
532
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
533
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
534
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
535
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
536
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
537
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
538
|
-
SOFTWARE.
|
|
539
|
-
|
|
540
|
-
```
|
|
541
|
-
|
|
542
512
|
### @newrelic/security-agent
|
|
543
513
|
|
|
544
|
-
This product includes source derived from [@newrelic/security-agent](https://github.com/newrelic/csec-node-agent) ([v1.
|
|
514
|
+
This product includes source derived from [@newrelic/security-agent](https://github.com/newrelic/csec-node-agent) ([v1.5.0](https://github.com/newrelic/csec-node-agent/tree/v1.5.0)), distributed under the [UNKNOWN License](https://github.com/newrelic/csec-node-agent/blob/v1.5.0/LICENSE):
|
|
545
515
|
|
|
546
516
|
```
|
|
547
517
|
## New Relic Software License v1.0
|
|
@@ -676,7 +646,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
676
646
|
|
|
677
647
|
### import-in-the-middle
|
|
678
648
|
|
|
679
|
-
This product includes source derived from [import-in-the-middle](https://github.com/nodejs/import-in-the-middle) ([v1.
|
|
649
|
+
This product includes source derived from [import-in-the-middle](https://github.com/nodejs/import-in-the-middle) ([v1.11.0](https://github.com/nodejs/import-in-the-middle/tree/v1.11.0)), distributed under the [Apache-2.0 License](https://github.com/nodejs/import-in-the-middle/blob/v1.11.0/LICENSE):
|
|
680
650
|
|
|
681
651
|
```
|
|
682
652
|
Apache License
|
|
@@ -1018,6 +988,36 @@ IN THE SOFTWARE.
|
|
|
1018
988
|
|
|
1019
989
|
```
|
|
1020
990
|
|
|
991
|
+
### require-in-the-middle
|
|
992
|
+
|
|
993
|
+
This product includes source derived from [require-in-the-middle](https://github.com/elastic/require-in-the-middle) ([v7.4.0](https://github.com/elastic/require-in-the-middle/tree/v7.4.0)), distributed under the [MIT License](https://github.com/elastic/require-in-the-middle/blob/v7.4.0/LICENSE):
|
|
994
|
+
|
|
995
|
+
```
|
|
996
|
+
The MIT License (MIT)
|
|
997
|
+
|
|
998
|
+
Copyright (c) 2016-2019, Thomas Watson Steen
|
|
999
|
+
Copyright (c) 2019-2023, Elasticsearch B.V.
|
|
1000
|
+
|
|
1001
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1002
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
1003
|
+
in the Software without restriction, including without limitation the rights
|
|
1004
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1005
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
1006
|
+
furnished to do so, subject to the following conditions:
|
|
1007
|
+
|
|
1008
|
+
The above copyright notice and this permission notice shall be included in all
|
|
1009
|
+
copies or substantial portions of the Software.
|
|
1010
|
+
|
|
1011
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1012
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1013
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1014
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1015
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1016
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1017
|
+
SOFTWARE.
|
|
1018
|
+
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
1021
|
### semver
|
|
1022
1022
|
|
|
1023
1023
|
This product includes source derived from [semver](https://github.com/npm/node-semver) ([v7.6.3](https://github.com/npm/node-semver/tree/v7.6.3)), distributed under the [ISC License](https://github.com/npm/node-semver/blob/v7.6.3/LICENSE):
|
|
@@ -1076,7 +1076,7 @@ SOFTWARE.
|
|
|
1076
1076
|
|
|
1077
1077
|
### @aws-sdk/client-s3
|
|
1078
1078
|
|
|
1079
|
-
This product includes source derived from [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3) ([v3.
|
|
1079
|
+
This product includes source derived from [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3) ([v3.632.0](https://github.com/aws/aws-sdk-js-v3/tree/v3.632.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.632.0/LICENSE):
|
|
1080
1080
|
|
|
1081
1081
|
```
|
|
1082
1082
|
Apache License
|
|
@@ -1285,7 +1285,7 @@ This product includes source derived from [@aws-sdk/client-s3](https://github.co
|
|
|
1285
1285
|
|
|
1286
1286
|
### @aws-sdk/s3-request-presigner
|
|
1287
1287
|
|
|
1288
|
-
This product includes source derived from [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3) ([v3.
|
|
1288
|
+
This product includes source derived from [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3) ([v3.632.0](https://github.com/aws/aws-sdk-js-v3/tree/v3.632.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.632.0/LICENSE):
|
|
1289
1289
|
|
|
1290
1290
|
```
|
|
1291
1291
|
Apache License
|
|
@@ -1940,7 +1940,7 @@ This product includes source derived from [@newrelic/newrelic-oss-cli](https://g
|
|
|
1940
1940
|
|
|
1941
1941
|
### @newrelic/test-utilities
|
|
1942
1942
|
|
|
1943
|
-
This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([
|
|
1943
|
+
This product includes source derived from [@newrelic/test-utilities](https://github.com/newrelic/node-test-utilities) ([v9.1.0](https://github.com/newrelic/node-test-utilities/tree/v9.1.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-test-utilities/blob/v9.1.0/LICENSE):
|
|
1944
1944
|
|
|
1945
1945
|
```
|
|
1946
1946
|
Apache License
|
|
@@ -2179,7 +2179,7 @@ THE SOFTWARE.
|
|
|
2179
2179
|
|
|
2180
2180
|
### @slack/bolt
|
|
2181
2181
|
|
|
2182
|
-
This product includes source derived from [@slack/bolt](https://github.com/slackapi/bolt) ([v3.
|
|
2182
|
+
This product includes source derived from [@slack/bolt](https://github.com/slackapi/bolt) ([v3.21.1](https://github.com/slackapi/bolt/tree/v3.21.1)), distributed under the [MIT License](https://github.com/slackapi/bolt/blob/v3.21.1/LICENSE):
|
|
2183
2183
|
|
|
2184
2184
|
```
|
|
2185
2185
|
The MIT License (MIT)
|
|
@@ -2683,7 +2683,7 @@ THE SOFTWARE.
|
|
|
2683
2683
|
|
|
2684
2684
|
### aws-sdk
|
|
2685
2685
|
|
|
2686
|
-
This product includes source derived from [aws-sdk](https://github.com/aws/aws-sdk-js) ([v2.
|
|
2686
|
+
This product includes source derived from [aws-sdk](https://github.com/aws/aws-sdk-js) ([v2.1677.0](https://github.com/aws/aws-sdk-js/tree/v2.1677.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js/blob/v2.1677.0/LICENSE.txt):
|
|
2687
2687
|
|
|
2688
2688
|
```
|
|
2689
2689
|
|
|
@@ -3111,7 +3111,7 @@ THE SOFTWARE.
|
|
|
3111
3111
|
|
|
3112
3112
|
### eslint-plugin-jsdoc
|
|
3113
3113
|
|
|
3114
|
-
This product includes source derived from [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) ([v48.
|
|
3114
|
+
This product includes source derived from [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) ([v48.11.0](https://github.com/gajus/eslint-plugin-jsdoc/tree/v48.11.0)), distributed under the [BSD-3-Clause License](https://github.com/gajus/eslint-plugin-jsdoc/blob/v48.11.0/LICENSE):
|
|
3115
3115
|
|
|
3116
3116
|
```
|
|
3117
3117
|
Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/)
|
|
@@ -4026,7 +4026,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
4026
4026
|
|
|
4027
4027
|
### self-cert
|
|
4028
4028
|
|
|
4029
|
-
This product includes source derived from [self-cert](https://github.com/jsumners/self-cert) ([v2.0.
|
|
4029
|
+
This product includes source derived from [self-cert](https://github.com/jsumners/self-cert) ([v2.0.1](https://github.com/jsumners/self-cert/tree/v2.0.1)), distributed under the [MIT License](https://github.com/jsumners/self-cert/blob/v2.0.1/Readme.md):
|
|
4030
4030
|
|
|
4031
4031
|
```
|
|
4032
4032
|
MIT License
|
|
@@ -4189,7 +4189,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
4189
4189
|
|
|
4190
4190
|
### @contrast/fn-inspect
|
|
4191
4191
|
|
|
4192
|
-
This product includes source derived from [@contrast/fn-inspect](https://github.com/Contrast-Security-Inc/node-fn-inspect) ([v4.
|
|
4192
|
+
This product includes source derived from [@contrast/fn-inspect](https://github.com/Contrast-Security-Inc/node-fn-inspect) ([v4.3.0](https://github.com/Contrast-Security-Inc/node-fn-inspect/tree/v4.3.0)), distributed under the [MIT License](https://github.com/Contrast-Security-Inc/node-fn-inspect/blob/v4.3.0/LICENSE):
|
|
4193
4193
|
|
|
4194
4194
|
```
|
|
4195
4195
|
Copyright 2022 Contrast Security, Inc
|
|
@@ -4215,7 +4215,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
4215
4215
|
|
|
4216
4216
|
### @newrelic/native-metrics
|
|
4217
4217
|
|
|
4218
|
-
This product includes source derived from [@newrelic/native-metrics](https://github.com/newrelic/node-native-metrics) ([
|
|
4218
|
+
This product includes source derived from [@newrelic/native-metrics](https://github.com/newrelic/node-native-metrics) ([v11.0.0](https://github.com/newrelic/node-native-metrics/tree/v11.0.0)), distributed under the [Apache-2.0 License](https://github.com/newrelic/node-native-metrics/blob/v11.0.0/LICENSE):
|
|
4219
4219
|
|
|
4220
4220
|
```
|
|
4221
4221
|
Apache License
|
package/api.js
CHANGED
|
@@ -32,6 +32,7 @@ const obfuscate = require('./lib/util/sql/obfuscate')
|
|
|
32
32
|
const { DESTINATIONS } = require('./lib/config/attribute-filter')
|
|
33
33
|
const parse = require('module-details-from-path')
|
|
34
34
|
const { isSimpleObject } = require('./lib/util/objects')
|
|
35
|
+
const { AsyncLocalStorage } = require('async_hooks')
|
|
35
36
|
|
|
36
37
|
/*
|
|
37
38
|
*
|
|
@@ -1902,4 +1903,52 @@ API.prototype.ignoreApdex = function ignoreApdex() {
|
|
|
1902
1903
|
transaction.ignoreApdex = true
|
|
1903
1904
|
}
|
|
1904
1905
|
|
|
1906
|
+
/**
|
|
1907
|
+
* Run a function with the passed in LLM context as the active context and return its return value.
|
|
1908
|
+
*
|
|
1909
|
+
* An example of setting a custom attribute:
|
|
1910
|
+
*
|
|
1911
|
+
* newrelic.withLlmCustomAttributes({'llm.someAttribute': 'someValue'}, () => {
|
|
1912
|
+
* return;
|
|
1913
|
+
* })
|
|
1914
|
+
* @param {Object} context LLM custom attributes context
|
|
1915
|
+
* @param {Function} callback The function to execute in context.
|
|
1916
|
+
*/
|
|
1917
|
+
API.prototype.withLlmCustomAttributes = function withLlmCustomAttributes(context, callback) {
|
|
1918
|
+
context = context || {}
|
|
1919
|
+
const metric = this.agent.metrics.getOrCreateMetric(
|
|
1920
|
+
NAMES.SUPPORTABILITY.API + '/withLlmCustomAttributes'
|
|
1921
|
+
)
|
|
1922
|
+
metric.incrementCallCount()
|
|
1923
|
+
|
|
1924
|
+
const transaction = this.agent.tracer.getTransaction()
|
|
1925
|
+
|
|
1926
|
+
if (!callback || typeof callback !== 'function') {
|
|
1927
|
+
logger.warn('withLlmCustomAttributes must be used with a valid callback')
|
|
1928
|
+
return
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
if (!transaction) {
|
|
1932
|
+
logger.warn('withLlmCustomAttributes must be called within the scope of a transaction.')
|
|
1933
|
+
return callback()
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
for (const [key, value] of Object.entries(context)) {
|
|
1937
|
+
if (typeof value === 'object' || typeof value === 'function') {
|
|
1938
|
+
logger.warn(`Invalid attribute type for ${key}. Skipped.`)
|
|
1939
|
+
delete context[key]
|
|
1940
|
+
} else if (key.indexOf('llm.') !== 0) {
|
|
1941
|
+
logger.warn(`Invalid attribute name ${key}. Renamed to "llm.${key}".`)
|
|
1942
|
+
delete context[key]
|
|
1943
|
+
context[`llm.${key}`] = value
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
transaction._llmContextManager = transaction._llmContextManager || new AsyncLocalStorage()
|
|
1948
|
+
const parentContext = transaction._llmContextManager.getStore() || {}
|
|
1949
|
+
|
|
1950
|
+
const fullContext = Object.assign({}, parentContext, context)
|
|
1951
|
+
return transaction._llmContextManager.run(fullContext, callback)
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1905
1954
|
module.exports = API
|
|
@@ -18,6 +18,7 @@ const { DESTINATIONS } = require('../../../config/attribute-filter')
|
|
|
18
18
|
const { AI } = require('../../../metrics/names')
|
|
19
19
|
const { RecorderSpec } = require('../../../shim/specs')
|
|
20
20
|
const InstrumentationDescriptor = require('../../../instrumentation-descriptor')
|
|
21
|
+
const { extractLlmContext } = require('../../../util/llm-utils')
|
|
21
22
|
|
|
22
23
|
let TRACKING_METRIC
|
|
23
24
|
|
|
@@ -55,7 +56,12 @@ function isStreamingEnabled({ commandName, config }) {
|
|
|
55
56
|
*/
|
|
56
57
|
function recordEvent({ agent, type, msg }) {
|
|
57
58
|
msg.serialize()
|
|
58
|
-
|
|
59
|
+
const llmContext = extractLlmContext(agent)
|
|
60
|
+
|
|
61
|
+
agent.customEventAggregator.add([
|
|
62
|
+
{ type, timestamp: Date.now() },
|
|
63
|
+
Object.assign({}, msg, llmContext)
|
|
64
|
+
])
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
/**
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const { MiddlewareSpec, MiddlewareMounterSpec, RenderSpec } = require('../../lib/shim/specs')
|
|
9
|
-
const { MIDDLEWARE_TYPE_NAMES } = require('../../lib/shim/webframework-shim/common')
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Express middleware generates traces where middleware are considered siblings
|
|
@@ -25,18 +24,8 @@ module.exports = function initialize(agent, express, moduleName, shim) {
|
|
|
25
24
|
return err !== 'route' && err !== 'router'
|
|
26
25
|
})
|
|
27
26
|
|
|
28
|
-
if (express.Router.use) {
|
|
29
|
-
wrapExpress4(shim, express)
|
|
30
|
-
} else {
|
|
31
|
-
wrapExpress3(shim, express)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function wrapExpress4(shim, express) {
|
|
36
|
-
// Wrap `use` and `route` which are hung off `Router` directly, not on a
|
|
37
|
-
// prototype.
|
|
38
27
|
shim.wrapMiddlewareMounter(
|
|
39
|
-
express.
|
|
28
|
+
express.application,
|
|
40
29
|
'use',
|
|
41
30
|
new MiddlewareMounterSpec({
|
|
42
31
|
route: shim.FIRST,
|
|
@@ -44,8 +33,13 @@ function wrapExpress4(shim, express) {
|
|
|
44
33
|
})
|
|
45
34
|
)
|
|
46
35
|
|
|
36
|
+
wrapExpressRouter(shim, express.Router.use ? express.Router : express.Router.prototype)
|
|
37
|
+
wrapResponse(shim, express.response)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function wrapExpressRouter(shim, router) {
|
|
47
41
|
shim.wrapMiddlewareMounter(
|
|
48
|
-
|
|
42
|
+
router,
|
|
49
43
|
'use',
|
|
50
44
|
new MiddlewareMounterSpec({
|
|
51
45
|
route: shim.FIRST,
|
|
@@ -53,7 +47,7 @@ function wrapExpress4(shim, express) {
|
|
|
53
47
|
})
|
|
54
48
|
)
|
|
55
49
|
|
|
56
|
-
shim.wrap(
|
|
50
|
+
shim.wrap(router, 'route', function wrapRoute(shim, fn) {
|
|
57
51
|
if (!shim.isFunction(fn)) {
|
|
58
52
|
return fn
|
|
59
53
|
}
|
|
@@ -89,7 +83,7 @@ function wrapExpress4(shim, express) {
|
|
|
89
83
|
})
|
|
90
84
|
|
|
91
85
|
shim.wrapMiddlewareMounter(
|
|
92
|
-
|
|
86
|
+
router,
|
|
93
87
|
'param',
|
|
94
88
|
new MiddlewareMounterSpec({
|
|
95
89
|
route: shim.FIRST,
|
|
@@ -105,56 +99,6 @@ function wrapExpress4(shim, express) {
|
|
|
105
99
|
}
|
|
106
100
|
})
|
|
107
101
|
)
|
|
108
|
-
|
|
109
|
-
wrapResponse(shim, express.response)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function wrapExpress3(shim, express) {
|
|
113
|
-
// In Express 3 the app returned from `express()` is actually a `connect` app
|
|
114
|
-
// which we have no access to before creation. We can not easily wrap the app
|
|
115
|
-
// because there are a lot of methods dangling on it that act on the app itself.
|
|
116
|
-
// Really we just care about apps being used as `request` event listeners on
|
|
117
|
-
// `http.Server` instances so we'll wrap that instead.
|
|
118
|
-
|
|
119
|
-
shim.wrapMiddlewareMounter(
|
|
120
|
-
express.Router.prototype,
|
|
121
|
-
'param',
|
|
122
|
-
new MiddlewareMounterSpec({
|
|
123
|
-
route: shim.FIRST,
|
|
124
|
-
wrapper: function wrapParamware(shim, middleware, fnName, route) {
|
|
125
|
-
return shim.recordParamware(
|
|
126
|
-
middleware,
|
|
127
|
-
new MiddlewareSpec({
|
|
128
|
-
name: route,
|
|
129
|
-
req: shim.FIRST,
|
|
130
|
-
next: shim.THIRD,
|
|
131
|
-
type: MIDDLEWARE_TYPE_NAMES.PARAMWARE
|
|
132
|
-
})
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
})
|
|
136
|
-
)
|
|
137
|
-
shim.wrapMiddlewareMounter(
|
|
138
|
-
express.Router.prototype,
|
|
139
|
-
'use',
|
|
140
|
-
new MiddlewareMounterSpec({
|
|
141
|
-
route: shim.FIRST,
|
|
142
|
-
wrapper: wrapMiddleware
|
|
143
|
-
})
|
|
144
|
-
)
|
|
145
|
-
shim.wrapMiddlewareMounter(
|
|
146
|
-
express.application,
|
|
147
|
-
'use',
|
|
148
|
-
new MiddlewareMounterSpec({
|
|
149
|
-
route: shim.FIRST,
|
|
150
|
-
wrapper: wrapMiddleware
|
|
151
|
-
})
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
// NOTE: Do not wrap application route methods in Express 3, they all just
|
|
155
|
-
// forward their arguments to the router.
|
|
156
|
-
wrapRouteMethods(shim, express.Router.prototype, shim.FIRST)
|
|
157
|
-
wrapResponse(shim, express.response)
|
|
158
102
|
}
|
|
159
103
|
|
|
160
104
|
function wrapRouteMethods(shim, route, path) {
|
|
@@ -115,10 +115,8 @@ function wrapMatchedRoute(shim, context) {
|
|
|
115
115
|
Object.defineProperty(context, '_matchedRoute', {
|
|
116
116
|
get: () => context[symbols.koaMatchedRoute],
|
|
117
117
|
set: (val) => {
|
|
118
|
-
const match = getLayerForTransactionName(context)
|
|
119
|
-
|
|
120
118
|
// match should never be undefined given _matchedRoute was set
|
|
121
|
-
if (
|
|
119
|
+
if (val) {
|
|
122
120
|
const currentSegment = shim.getActiveSegment()
|
|
123
121
|
|
|
124
122
|
// Segment/Transaction may be null, see:
|
|
@@ -131,7 +129,7 @@ function wrapMatchedRoute(shim, context) {
|
|
|
131
129
|
transaction.nameState.popPath()
|
|
132
130
|
}
|
|
133
131
|
|
|
134
|
-
transaction.nameState.appendPath(
|
|
132
|
+
transaction.nameState.appendPath(val)
|
|
135
133
|
transaction.nameState.markPath()
|
|
136
134
|
}
|
|
137
135
|
}
|
|
@@ -169,22 +167,6 @@ function wrapResponseStatus(shim, context) {
|
|
|
169
167
|
})
|
|
170
168
|
}
|
|
171
169
|
|
|
172
|
-
function getLayerForTransactionName(context) {
|
|
173
|
-
// Context.matched might be null
|
|
174
|
-
// See https://github.com/newrelic/node-newrelic-koa/pull/29
|
|
175
|
-
if (!context.matched) {
|
|
176
|
-
return null
|
|
177
|
-
}
|
|
178
|
-
for (let i = context.matched.length - 1; i >= 0; i--) {
|
|
179
|
-
const layer = context.matched[i]
|
|
180
|
-
if (layer.opts.end) {
|
|
181
|
-
return layer
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return null
|
|
186
|
-
}
|
|
187
|
-
|
|
188
170
|
function getInheritedPropertyDescriptor(obj, property) {
|
|
189
171
|
let proto = obj
|
|
190
172
|
let descriptor = null
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
const {
|
|
8
8
|
AI: { LANGCHAIN }
|
|
9
9
|
} = require('../../metrics/names')
|
|
10
|
+
const { extractLlmContext } = require('../../util/llm-utils')
|
|
10
11
|
|
|
11
12
|
const common = module.exports
|
|
12
13
|
|
|
@@ -49,7 +50,12 @@ common.mergeMetadata = function mergeMetadata(localMeta = {}, paramsMeta = {}) {
|
|
|
49
50
|
*/
|
|
50
51
|
common.recordEvent = function recordEvent({ agent, type, msg, pkgVersion }) {
|
|
51
52
|
agent.metrics.getOrCreateMetric(`${LANGCHAIN.TRACKING_PREFIX}/${pkgVersion}`).incrementCallCount()
|
|
52
|
-
|
|
53
|
+
const llmContext = extractLlmContext(agent)
|
|
54
|
+
|
|
55
|
+
agent.customEventAggregator.add([
|
|
56
|
+
{ type, timestamp: Date.now() },
|
|
57
|
+
Object.assign({}, msg, llmContext)
|
|
58
|
+
])
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
/**
|
|
@@ -22,8 +22,16 @@ module.exports = [
|
|
|
22
22
|
onRequire: cbManagerInstrumentation
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
+
// This block is for catching langchain internal imports
|
|
26
|
+
// of the callback manager. See:
|
|
27
|
+
// https://github.com/elastic/require-in-the-middle/pull/88#issuecomment-2124940546
|
|
25
28
|
type: InstrumentationDescriptor.TYPE_GENERIC,
|
|
26
|
-
moduleName: '@langchain/core/dist/
|
|
29
|
+
moduleName: '@langchain/core/dist/callbacks/manager.cjs',
|
|
30
|
+
onRequire: cbManagerInstrumentation
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: InstrumentationDescriptor.TYPE_GENERIC,
|
|
34
|
+
moduleName: '@langchain/core/runnables',
|
|
27
35
|
onRequire: runnableInstrumentation
|
|
28
36
|
},
|
|
29
37
|
{
|
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
LlmErrorMessage
|
|
13
13
|
} = require('../../lib/llm-events/openai')
|
|
14
14
|
const { RecorderSpec } = require('../../lib/shim/specs')
|
|
15
|
+
const { extractLlmContext } = require('../util/llm-utils')
|
|
15
16
|
|
|
16
17
|
const MIN_VERSION = '4.0.0'
|
|
17
18
|
const MIN_STREAM_VERSION = '4.12.2'
|
|
@@ -75,7 +76,12 @@ function decorateSegment({ shim, result, apiKey }) {
|
|
|
75
76
|
* @param {object} params.msg LLM event
|
|
76
77
|
*/
|
|
77
78
|
function recordEvent({ agent, type, msg }) {
|
|
78
|
-
|
|
79
|
+
const llmContext = extractLlmContext(agent)
|
|
80
|
+
|
|
81
|
+
agent.customEventAggregator.add([
|
|
82
|
+
{ type, timestamp: Date.now() },
|
|
83
|
+
Object.assign({}, msg, llmContext)
|
|
84
|
+
])
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
/**
|
|
@@ -106,38 +106,45 @@ function isLambdaProxyEvent(event) {
|
|
|
106
106
|
return isGatewayV1Event(event) || isGatewayV2Event(event)
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
109
|
+
const v1Keys = [
|
|
110
|
+
'body',
|
|
111
|
+
'headers',
|
|
112
|
+
'httpMethod',
|
|
113
|
+
'isBase64Encoded',
|
|
114
|
+
'multiValueHeaders',
|
|
115
|
+
'multiValueQueryStringParameters',
|
|
116
|
+
'path',
|
|
117
|
+
'pathParameters',
|
|
118
|
+
'queryStringParameters',
|
|
119
|
+
'requestContext',
|
|
120
|
+
'resource',
|
|
121
|
+
'stageVariables',
|
|
122
|
+
'version'
|
|
123
|
+
].join(',')
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
function isGatewayV1Event(event) {
|
|
126
|
+
const keys = Object.keys(event).sort().join(',')
|
|
127
|
+
return keys === v1Keys && event?.version === '1.0'
|
|
124
128
|
}
|
|
125
129
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
130
|
+
const v2Keys = [
|
|
131
|
+
'body',
|
|
132
|
+
'cookies',
|
|
133
|
+
'headers',
|
|
134
|
+
'isBase64Encoded',
|
|
135
|
+
'pathParameters',
|
|
136
|
+
'queryStringParameters',
|
|
137
|
+
'rawPath',
|
|
138
|
+
'rawQueryString',
|
|
139
|
+
'requestContext',
|
|
140
|
+
'routeKey',
|
|
141
|
+
'stageVariables',
|
|
142
|
+
'version'
|
|
143
|
+
].join(',')
|
|
139
144
|
|
|
140
|
-
|
|
145
|
+
function isGatewayV2Event(event) {
|
|
146
|
+
const keys = Object.keys(event).sort().join(',')
|
|
147
|
+
return keys === v2Keys && event?.version === '2.0'
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
/**
|
|
@@ -155,5 +162,7 @@ module.exports = {
|
|
|
155
162
|
LambdaProxyWebRequest,
|
|
156
163
|
LambdaProxyWebResponse,
|
|
157
164
|
isLambdaProxyEvent,
|
|
158
|
-
isValidLambdaProxyResponse
|
|
165
|
+
isValidLambdaProxyResponse,
|
|
166
|
+
isGatewayV1Event,
|
|
167
|
+
isGatewayV2Event
|
|
159
168
|
}
|
package/lib/shimmer.js
CHANGED
|
@@ -11,7 +11,7 @@ const fs = require('./util/unwrapped-core').fs
|
|
|
11
11
|
const logger = require('./logger').child({ component: 'shimmer' })
|
|
12
12
|
const INSTRUMENTATIONS = require('./instrumentations')()
|
|
13
13
|
const shims = require('./shim')
|
|
14
|
-
const { Hook } = require('
|
|
14
|
+
const { Hook } = require('require-in-the-middle')
|
|
15
15
|
const IitmHook = require('import-in-the-middle')
|
|
16
16
|
const { nrEsmProxy } = require('./symbols')
|
|
17
17
|
const isAbsolutePath = require('./util/is-absolute-path')
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
exports = module.exports = { extractLlmContext, extractLlmAttributes }
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extract LLM attributes from the LLM context
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} context LLM context object
|
|
14
|
+
* @returns {Object} LLM custom attributes
|
|
15
|
+
*/
|
|
16
|
+
function extractLlmAttributes(context) {
|
|
17
|
+
return Object.keys(context).reduce((result, key) => {
|
|
18
|
+
if (key.indexOf('llm.') === 0) {
|
|
19
|
+
result[key] = context[key]
|
|
20
|
+
}
|
|
21
|
+
return result
|
|
22
|
+
}, {})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Extract LLM context from the active transaction
|
|
27
|
+
*
|
|
28
|
+
* @param {Agent} agent NR agent instance
|
|
29
|
+
* @returns {Object} LLM context object
|
|
30
|
+
*/
|
|
31
|
+
function extractLlmContext(agent) {
|
|
32
|
+
const context = agent.tracer.getTransaction()?._llmContextManager?.getStore() || {}
|
|
33
|
+
return extractLlmAttributes(context)
|
|
34
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newrelic",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.3.0",
|
|
4
4
|
"author": "New Relic Node.js agent team <nodejs@newrelic.com>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"contributors": [
|
|
@@ -164,9 +164,9 @@
|
|
|
164
164
|
"integration": "npm run prepare-test && npm run sub-install && time c8 -o ./coverage/integration borp --timeout 600000 --reporter ./test/lib/test-reporter.mjs 'test/integration/**/*.tap.js'",
|
|
165
165
|
"integration:esm": "NODE_OPTIONS='--loader=./esm-loader.mjs' time c8 -o ./coverage/integration-esm borp --reporter ./test/lib/test-reporter.mjs 'test/integration/**/*.tap.mjs'",
|
|
166
166
|
"prepare-test": "npm run ssl && npm run docker-env",
|
|
167
|
-
"lint": "eslint ./*.{js,mjs} lib test bin
|
|
168
|
-
"lint:fix": "eslint --fix, ./*.{js,mjs} lib test bin
|
|
169
|
-
"public-docs": "jsdoc -c ./jsdoc-conf.jsonc
|
|
167
|
+
"lint": "eslint ./*.{js,mjs} lib test bin",
|
|
168
|
+
"lint:fix": "eslint --fix, ./*.{js,mjs} lib test bin",
|
|
169
|
+
"public-docs": "jsdoc -c ./jsdoc-conf.jsonc",
|
|
170
170
|
"publish-docs": "./bin/publish-docs.sh",
|
|
171
171
|
"services": "DOCKER_PLATFORM=linux/$(uname -m) docker compose up -d --wait",
|
|
172
172
|
"services:stop": "docker compose down",
|
|
@@ -197,7 +197,6 @@
|
|
|
197
197
|
"dependencies": {
|
|
198
198
|
"@grpc/grpc-js": "^1.9.4",
|
|
199
199
|
"@grpc/proto-loader": "^0.7.5",
|
|
200
|
-
"@newrelic/ritm": "^7.2.0",
|
|
201
200
|
"@newrelic/security-agent": "^1.3.0",
|
|
202
201
|
"@tyriar/fibonacci-heap": "^2.0.7",
|
|
203
202
|
"concat-stream": "^2.0.0",
|
|
@@ -207,6 +206,7 @@
|
|
|
207
206
|
"json-stringify-safe": "^5.0.0",
|
|
208
207
|
"module-details-from-path": "^1.0.3",
|
|
209
208
|
"readable-stream": "^3.6.1",
|
|
209
|
+
"require-in-the-middle": "^7.4.0",
|
|
210
210
|
"semver": "^7.5.2",
|
|
211
211
|
"winston-transport": "^4.5.0"
|
|
212
212
|
},
|
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
"@koa/router": "^12.0.1",
|
|
222
222
|
"@newrelic/eslint-config": "^0.3.0",
|
|
223
223
|
"@newrelic/newrelic-oss-cli": "^0.1.2",
|
|
224
|
-
"@newrelic/test-utilities": "^
|
|
224
|
+
"@newrelic/test-utilities": "^9.1.0",
|
|
225
225
|
"@octokit/rest": "^18.0.15",
|
|
226
226
|
"@slack/bolt": "^3.7.0",
|
|
227
227
|
"@smithy/eventstream-codec": "^2.2.0",
|