newrelic 12.7.0 → 12.8.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 CHANGED
@@ -1,3 +1,78 @@
1
+ ### v12.8.1 (2024-12-04)
2
+
3
+ #### Bug fixes
4
+
5
+ * Fixed matching for ALB and API Gateway (v1 & v2) events for Lambda ([#2780](https://github.com/newrelic/node-newrelic/pull/2780)) ([2f1a6c6](https://github.com/newrelic/node-newrelic/commit/2f1a6c6dc6e4408c62b074d71a95b67cc0926785))
6
+ * Updated `mysql2` instrumentation to work with 3.11.5+ ([#2811](https://github.com/newrelic/node-newrelic/pull/2811)) ([3ec4fee](https://github.com/newrelic/node-newrelic/commit/3ec4fee486c6f609426deddb7cee8372e4dc1192))
7
+
8
+ #### Documentation
9
+
10
+ * Fixed changelog to group the labels in logs work ([#2776](https://github.com/newrelic/node-newrelic/pull/2776)) ([04271da](https://github.com/newrelic/node-newrelic/commit/04271dae2306f54d885aa723eebc3041edee2575))
11
+ * Fixed links to next.js apps ([#2812](https://github.com/newrelic/node-newrelic/pull/2812)) ([834440c](https://github.com/newrelic/node-newrelic/commit/834440caee017fe632b354d20112c3016587064b))
12
+ * Updated compatibility report ([#2809](https://github.com/newrelic/node-newrelic/pull/2809)) ([fc1fbda](https://github.com/newrelic/node-newrelic/commit/fc1fbdaf69c82caf4d7933c7fdd4eec395648e63))
13
+
14
+ #### Tests
15
+
16
+ * Migrated `test/integration/api` tests to `node:test` ([#2787](https://github.com/newrelic/node-newrelic/pull/2787)) ([03b01a3](https://github.com/newrelic/node-newrelic/commit/03b01a3bf40c8902c29c772aee4d70af8020ae62))
17
+ * Migrated `test/integration/core` tests to `node:test` ([#2781](https://github.com/newrelic/node-newrelic/pull/2781)) ([36bc0e7](https://github.com/newrelic/node-newrelic/commit/36bc0e7f97f1bbde522031942ec0cc7c1d4c1349))
18
+ * Migrated `test/integration/instrumentation` tests to `node:test` ([#2784](https://github.com/newrelic/node-newrelic/pull/2784)) ([963fb30](https://github.com/newrelic/node-newrelic/commit/963fb30087e1b9a7bf12c4ae71b8252a872e90e5))
19
+ * Migrated `test/integration/transaction` tests to `node:test` ([#2783](https://github.com/newrelic/node-newrelic/pull/2783)) ([68e1a0c](https://github.com/newrelic/node-newrelic/commit/68e1a0c8c529702fafb29a7684f6982b0d3c48cb))
20
+ * Migrated `test/integration/utilization` tests to node `node:test` ([#2794](https://github.com/newrelic/node-newrelic/pull/2794)) ([db237e9](https://github.com/newrelic/node-newrelic/commit/db237e9b8811554472b4f83100b3266ce52dc38b))
21
+ * Migrated `test/smoke/api` tests to `node:test` ([#2772](https://github.com/newrelic/node-newrelic/pull/2772)) ([af3bbcd](https://github.com/newrelic/node-newrelic/commit/af3bbcddd1e9ed28fdea32b2837bf509737181cc))
22
+ * Migrated CAT integration tests to `node:test` ([#2778](https://github.com/newrelic/node-newrelic/pull/2778)) ([bd9df5f](https://github.com/newrelic/node-newrelic/commit/bd9df5f0def633391762a191c16886735cddf9d2))
23
+ * Migrated integration tests at root to `node:test` ([#2803](https://github.com/newrelic/node-newrelic/pull/2803)) ([a7ef080](https://github.com/newrelic/node-newrelic/commit/a7ef080296b79d5fb8d313aa2bd9d474904e0a22))
24
+ * Migrated root smoke tests to `node:test` ([#2771](https://github.com/newrelic/node-newrelic/pull/2771)) ([78f2709](https://github.com/newrelic/node-newrelic/commit/78f2709a24328225f0c3c2392cf0a3b8072a877f))
25
+ * Migrated smoke tests in `test/smoke/agent`, `test/smoke/e2e`, and `test/smoke/index` to `node:test` ([#2774](https://github.com/newrelic/node-newrelic/pull/2774)) ([440a0af](https://github.com/newrelic/node-newrelic/commit/440a0af5545c0585d1bb5036b950f201444566db))
26
+ * Removed `t.diagnostic` as they are better suited as code comments ([#2786](https://github.com/newrelic/node-newrelic/pull/2786)) ([ee24027](https://github.com/newrelic/node-newrelic/commit/ee24027539aa2a6b5c8ab4c49529ff7f4fb8f269))
27
+ * Fixed flaky test on macOS ([#2790](https://github.com/newrelic/node-newrelic/pull/2790)) ([eebf06b](https://github.com/newrelic/node-newrelic/commit/eebf06b16c86cd40402c8d5566e01ca140802b24))
28
+ * Removed reference to `pino` internals ([#2805](https://github.com/newrelic/node-newrelic/pull/2805)) ([0382ee2](https://github.com/newrelic/node-newrelic/commit/0382ee26342546467f2f3b93be1c82d74e9d0123))
29
+ * Restricted `mysql2` version to get CI working ([#2808](https://github.com/newrelic/node-newrelic/pull/2808)) ([ad60ed4](https://github.com/newrelic/node-newrelic/commit/ad60ed4faf69d7c7938d63f335186323327e350f))
30
+ * Updated agent integration tests to `node:test` ([#2782](https://github.com/newrelic/node-newrelic/pull/2782)) ([d556512](https://github.com/newrelic/node-newrelic/commit/d556512ffebe3f38887aae65706dc5f1da4122d8))
31
+ * Updated config integration tests to `node:test` ([#2777](https://github.com/newrelic/node-newrelic/pull/2777)) ([fe8d2df](https://github.com/newrelic/node-newrelic/commit/fe8d2df36ccc7d818bbc7350985034767ca221b5))
32
+ * Updated distributed-tracing integration tests to `node:test` ([#2798](https://github.com/newrelic/node-newrelic/pull/2798)) ([83ad1f3](https://github.com/newrelic/node-newrelic/commit/83ad1f3e72f06211993b5dcbc2a5af4a27b259fe))
33
+ * Updated `grpc` integration tests to `node:test` ([#2789](https://github.com/newrelic/node-newrelic/pull/2789)) ([ea8f743](https://github.com/newrelic/node-newrelic/commit/ea8f743c7ef0d8bad0aa25f77b239ea18da59368))
34
+ * Updated index, issue-2155, and metric integration tests to `node:test` ([#2801](https://github.com/newrelic/node-newrelic/pull/2801)) ([80b55c2](https://github.com/newrelic/node-newrelic/commit/80b55c211aa9712ba79e39b236257583d4ccffd3))
35
+ * Updated `q`, `superagent`, and `when` tests to `node:test` ([#2773](https://github.com/newrelic/node-newrelic/pull/2773)) ([ff2d8d0](https://github.com/newrelic/node-newrelic/commit/ff2d8d02df8f602adbed3e361763ed406b891d21))
36
+ * Updated shimmer, uninstrumented, environment, flatten, and logger integration tests to `node:test` ([#2802](https://github.com/newrelic/node-newrelic/pull/2802)) ([83fd7ee](https://github.com/newrelic/node-newrelic/commit/83fd7ee912f5548b651bfa4c1ad7d7cbbc304092))
37
+ * Added per test file timing to test reporter ([#2785](https://github.com/newrelic/node-newrelic/pull/2785)) ([00d9940](https://github.com/newrelic/node-newrelic/commit/00d994086a228a096aaabb1f7f8af1f2f5ffc954))
38
+
39
+ ### v12.8.0 (2024-11-19)
40
+
41
+ #### Features
42
+
43
+ * Added new configuration options to add custom tags (labels) to logs ([#2743](https://github.com/newrelic/node-newrelic/pull/2743)) ([d20c874](https://github.com/newrelic/node-newrelic/commit/d20c874638ebb19f8888003d4402bce17e56360f))
44
+ * With custom tags on logs, platform engineers can easily filter, search, and correlate log data for faster and more efficient troubleshooting, improved performance, and optimized resource utilization. To learn more about this feature see the [documentation](https://docs.newrelic.com/docs/logs/logs-context/custom-tags-agent-forwarder-logs/)
45
+ * To enable set `config.application_logging.forwarding.labels.enabled` to `true` or the environment variable `NEW_RELIC_APPLICATION_LOGGING_FORWARDING_LABELS_ENABLED` to `true` ([#2727](https://github.com/newrelic/node-newrelic/pull/2727)) ([36adb13](https://github.com/newrelic/node-newrelic/commit/36adb13caad41a5df5a5fa9345b9dcb9061db969))
46
+ * To exclude labels that were set on application from logs use `config.application_logging.forwarding.labels.exclude` or the environment variable `NEW_RELIC_APPLICATION_LOGGING_FORWARDING_LABELS_EXCLUDE`
47
+ * Added support for Bedrock Claude 3.5 invoke model user request ([#2721](https://github.com/newrelic/node-newrelic/pull/2721)) ([a901a24](https://github.com/newrelic/node-newrelic/commit/a901a2499e73e0f1142054ead53e7b99df94b201))
48
+ * Moved `entity.guid`, `entity.name`, `entity.type`, and `hostname` to `common.attributes` on logs payload instead of in every log message ([#2736](https://github.com/newrelic/node-newrelic/pull/2736)) ([a7f14de](https://github.com/newrelic/node-newrelic/commit/a7f14def489000ab7492b01155069b1a084eeb36))
49
+
50
+ #### Bug fixes
51
+
52
+ * Corrected expected shape of user input in get Prompt() ([#2741](https://github.com/newrelic/node-newrelic/pull/2741)) ([a8eef8b](https://github.com/newrelic/node-newrelic/commit/a8eef8b0f80ec2b0db5834a722a69f58a32b5676))
53
+
54
+ #### Documentation
55
+
56
+ * Updated compatibility report ([#2755](https://github.com/newrelic/node-newrelic/pull/2755)) ([459a3f1](https://github.com/newrelic/node-newrelic/commit/459a3f19ee080a3a2e560636ce087f9e91bc529e))
57
+
58
+ #### Miscellaneous chores
59
+
60
+ * Fixed test reporter ([#2751](https://github.com/newrelic/node-newrelic/pull/2751)) ([5878ef9](https://github.com/newrelic/node-newrelic/commit/5878ef9844fd56038d08e3b2f8cd9e26ba8c4c92))
61
+ * Improved unit test speed ([#2728](https://github.com/newrelic/node-newrelic/pull/2728)) ([9640030](https://github.com/newrelic/node-newrelic/commit/96400304e451502ce2f09b569b46eaff271fd9ab))
62
+
63
+ #### Tests
64
+
65
+ * Fixed two assertions to work against older versions of `openai` ([#2726](https://github.com/newrelic/node-newrelic/pull/2726)) ([8996fc3](https://github.com/newrelic/node-newrelic/commit/8996fc3538735d7ad2d447bc7c4221b08c6c2be5))
66
+ * Migrated `ioredis`, `prisma` and `undici` versioned tests to `node:test` ([#2746](https://github.com/newrelic/node-newrelic/pull/2746)) ([449ae03](https://github.com/newrelic/node-newrelic/commit/449ae03883d2a5e92d11590372993eedc976ab99))
67
+ * Migrated `memcached`, `nestjs`, and `restify` versioned tests to `node:test` ([#2752](https://github.com/newrelic/node-newrelic/pull/2752)) ([653f614](https://github.com/newrelic/node-newrelic/commit/653f61410a0258683ac104cd8b8b2e7ae7c61043))
68
+ * Migrated `nextjs` versioned tests to `node:test` ([#2749](https://github.com/newrelic/node-newrelic/pull/2749)) ([d385af6](https://github.com/newrelic/node-newrelic/commit/d385af69c84a5425cee9ff19eaeadcba9e63a761))
69
+ * Migrated `redis` versioned tests to `node:test` ([#2725](https://github.com/newrelic/node-newrelic/pull/2725)) ([9752827](https://github.com/newrelic/node-newrelic/commit/97528270c70ecaac9161f4eb0cc78ffcc482be36))
70
+ * Updated `hapi` tests to `node:test` ([#2722](https://github.com/newrelic/node-newrelic/pull/2722)) ([636899b](https://github.com/newrelic/node-newrelic/commit/636899b487e196572a3bc0970e7338d0c9f113cf))
71
+ * Updated `kafkajs`, `langchain`, & `openai` tests to `node:test` ([#2723](https://github.com/newrelic/node-newrelic/pull/2723)) ([b6e4c5d](https://github.com/newrelic/node-newrelic/commit/b6e4c5d4c59032a615fea6d12623a881a6211917))
72
+ * Updated `koa` tests to `node:test` ([#2744](https://github.com/newrelic/node-newrelic/pull/2744)) ([86c22a4](https://github.com/newrelic/node-newrelic/commit/86c22a4813ec5a63ae8bd04f7d9d013979ac34ed))
73
+ * Updated `mongodb` tests to `node:test` ([#2738](https://github.com/newrelic/node-newrelic/pull/2738)) ([295e7e6](https://github.com/newrelic/node-newrelic/commit/295e7e6441b7220022ce4fcaaf33054945a678b0))
74
+ * Updated `pg` and `pg-esm` tests to `node:test` ([#2750](https://github.com/newrelic/node-newrelic/pull/2750)) ([40aea36](https://github.com/newrelic/node-newrelic/commit/40aea36320d15b201800431268be2c3d4c794a7b))
75
+
1
76
  ### v12.7.0 (2024-11-11)
2
77
 
3
78
  #### Features
package/README.md CHANGED
@@ -81,8 +81,8 @@ If you are having trouble getting the `newrelic` package to instrument Next.js,
81
81
  ### Next.js example projects
82
82
  The following example applications show how to load the `newrelic` instrumentation, inject browser agent, and handle errors:
83
83
 
84
- * [Pages Router example](https://github.com/newrelic/newrelic-node-examples/tree/58f760e828c45d90391bda3f66764d4420ba4990/nextjs-legacy)
85
- * [App Router example](https://github.com/newrelic/newrelic-node-examples/tree/58f760e828c45d90391bda3f66764d4420ba4990/nextjs-app-router)
84
+ * [Pages Router example](https://github.com/newrelic/newrelic-node-examples/tree/9415503f3bd78fa5d87a7214596d51c946199474/nextjs/nextjs-legacy)
85
+ * [App Router example](https://github.com/newrelic/newrelic-node-examples/tree/9415503f3bd78fa5d87a7214596d51c946199474/nextjs/nextjs-app-router)
86
86
 
87
87
  ### Custom Next.js servers
88
88
 
@@ -75,7 +75,6 @@ code, the source code can be found at [https://github.com/newrelic/node-newrelic
75
75
  * [sinon](#sinon)
76
76
  * [superagent](#superagent)
77
77
  * [tap](#tap)
78
- * [temp](#temp)
79
78
 
80
79
  **[optionalDependencies](#optionalDependencies)**
81
80
 
@@ -1042,7 +1041,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1042
1041
 
1043
1042
  ### winston-transport
1044
1043
 
1045
- This product includes source derived from [winston-transport](https://github.com/winstonjs/winston-transport) ([v4.8.0](https://github.com/winstonjs/winston-transport/tree/v4.8.0)), distributed under the [MIT License](https://github.com/winstonjs/winston-transport/blob/v4.8.0/LICENSE):
1044
+ This product includes source derived from [winston-transport](https://github.com/winstonjs/winston-transport) ([v4.7.1](https://github.com/winstonjs/winston-transport/tree/v4.7.1)), distributed under the [MIT License](https://github.com/winstonjs/winston-transport/blob/v4.7.1/LICENSE):
1046
1045
 
1047
1046
  ```
1048
1047
  The MIT License (MIT)
@@ -1075,7 +1074,7 @@ SOFTWARE.
1075
1074
 
1076
1075
  ### @aws-sdk/client-s3
1077
1076
 
1078
- This product includes source derived from [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3) ([v3.676.0](https://github.com/aws/aws-sdk-js-v3/tree/v3.676.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.676.0/LICENSE):
1077
+ This product includes source derived from [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3) ([v3.621.0](https://github.com/aws/aws-sdk-js-v3/tree/v3.621.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.621.0/LICENSE):
1079
1078
 
1080
1079
  ```
1081
1080
  Apache License
@@ -1284,7 +1283,7 @@ This product includes source derived from [@aws-sdk/client-s3](https://github.co
1284
1283
 
1285
1284
  ### @aws-sdk/s3-request-presigner
1286
1285
 
1287
- This product includes source derived from [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3) ([v3.676.0](https://github.com/aws/aws-sdk-js-v3/tree/v3.676.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.676.0/LICENSE):
1286
+ This product includes source derived from [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3) ([v3.621.0](https://github.com/aws/aws-sdk-js-v3/tree/v3.621.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js-v3/blob/v3.621.0/LICENSE):
1288
1287
 
1289
1288
  ```
1290
1289
  Apache License
@@ -1493,7 +1492,7 @@ This product includes source derived from [@aws-sdk/s3-request-presigner](https:
1493
1492
 
1494
1493
  ### @koa/router
1495
1494
 
1496
- This product includes source derived from [@koa/router](https://github.com/koajs/router) ([v12.0.2](https://github.com/koajs/router/tree/v12.0.2)), distributed under the [MIT License](https://github.com/koajs/router/blob/v12.0.2/LICENSE):
1495
+ This product includes source derived from [@koa/router](https://github.com/koajs/router) ([v12.0.1](https://github.com/koajs/router/tree/v12.0.1)), distributed under the [MIT License](https://github.com/koajs/router/blob/v12.0.1/LICENSE):
1497
1496
 
1498
1497
  ```
1499
1498
  The MIT License (MIT)
@@ -2207,7 +2206,7 @@ THE SOFTWARE.
2207
2206
 
2208
2207
  ### @slack/bolt
2209
2208
 
2210
- This product includes source derived from [@slack/bolt](https://github.com/slackapi/bolt) ([v3.22.0](https://github.com/slackapi/bolt/tree/v3.22.0)), distributed under the [MIT License](https://github.com/slackapi/bolt/blob/v3.22.0/LICENSE):
2209
+ This product includes source derived from [@slack/bolt](https://github.com/slackapi/bolt) ([v3.19.0](https://github.com/slackapi/bolt/tree/v3.19.0)), distributed under the [MIT License](https://github.com/slackapi/bolt/blob/v3.19.0/LICENSE):
2211
2210
 
2212
2211
  ```
2213
2212
  The MIT License (MIT)
@@ -2684,7 +2683,7 @@ SOFTWARE.
2684
2683
 
2685
2684
  ### async
2686
2685
 
2687
- This product includes source derived from [async](https://github.com/caolan/async) ([v3.2.6](https://github.com/caolan/async/tree/v3.2.6)), distributed under the [MIT License](https://github.com/caolan/async/blob/v3.2.6/LICENSE):
2686
+ This product includes source derived from [async](https://github.com/caolan/async) ([v3.2.5](https://github.com/caolan/async/tree/v3.2.5)), distributed under the [MIT License](https://github.com/caolan/async/blob/v3.2.5/LICENSE):
2688
2687
 
2689
2688
  ```
2690
2689
  Copyright (c) 2010-2018 Caolan McMahon
@@ -2711,7 +2710,7 @@ THE SOFTWARE.
2711
2710
 
2712
2711
  ### aws-sdk
2713
2712
 
2714
- This product includes source derived from [aws-sdk](https://github.com/aws/aws-sdk-js) ([v2.1691.0](https://github.com/aws/aws-sdk-js/tree/v2.1691.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js/blob/v2.1691.0/LICENSE.txt):
2713
+ This product includes source derived from [aws-sdk](https://github.com/aws/aws-sdk-js) ([v2.1665.0](https://github.com/aws/aws-sdk-js/tree/v2.1665.0)), distributed under the [Apache-2.0 License](https://github.com/aws/aws-sdk-js/blob/v2.1665.0/LICENSE.txt):
2715
2714
 
2716
2715
  ```
2717
2716
 
@@ -2921,7 +2920,7 @@ This product includes source derived from [aws-sdk](https://github.com/aws/aws-s
2921
2920
 
2922
2921
  ### borp
2923
2922
 
2924
- This product includes source derived from [borp](https://github.com/mcollina/borp) ([v0.18.0](https://github.com/mcollina/borp/tree/v0.18.0)), distributed under the [MIT License](https://github.com/mcollina/borp/blob/v0.18.0/LICENSE):
2923
+ This product includes source derived from [borp](https://github.com/mcollina/borp) ([v0.19.0](https://github.com/mcollina/borp/tree/v0.19.0)), distributed under the [MIT License](https://github.com/mcollina/borp/blob/v0.19.0/LICENSE):
2925
2924
 
2926
2925
  ```
2927
2926
  MIT License
@@ -3139,7 +3138,7 @@ THE SOFTWARE.
3139
3138
 
3140
3139
  ### eslint-plugin-jsdoc
3141
3140
 
3142
- 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):
3141
+ This product includes source derived from [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) ([v48.10.2](https://github.com/gajus/eslint-plugin-jsdoc/tree/v48.10.2)), distributed under the [BSD-3-Clause License](https://github.com/gajus/eslint-plugin-jsdoc/blob/v48.10.2/LICENSE):
3143
3142
 
3144
3143
  ```
3145
3144
  Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/)
@@ -3344,7 +3343,7 @@ Library.
3344
3343
 
3345
3344
  ### eslint
3346
3345
 
3347
- This product includes source derived from [eslint](https://github.com/eslint/eslint) ([v8.57.1](https://github.com/eslint/eslint/tree/v8.57.1)), distributed under the [MIT License](https://github.com/eslint/eslint/blob/v8.57.1/LICENSE):
3346
+ This product includes source derived from [eslint](https://github.com/eslint/eslint) ([v8.57.0](https://github.com/eslint/eslint/tree/v8.57.0)), distributed under the [MIT License](https://github.com/eslint/eslint/blob/v8.57.0/LICENSE):
3348
3347
 
3349
3348
  ```
3350
3349
  Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
@@ -3371,7 +3370,7 @@ THE SOFTWARE.
3371
3370
 
3372
3371
  ### express
3373
3372
 
3374
- This product includes source derived from [express](https://github.com/expressjs/express) ([v4.21.1](https://github.com/expressjs/express/tree/v4.21.1)), distributed under the [MIT License](https://github.com/expressjs/express/blob/v4.21.1/LICENSE):
3373
+ This product includes source derived from [express](https://github.com/expressjs/express) ([v4.19.2](https://github.com/expressjs/express/tree/v4.19.2)), distributed under the [MIT License](https://github.com/expressjs/express/blob/v4.19.2/LICENSE):
3375
3374
 
3376
3375
  ```
3377
3376
  (The MIT License)
@@ -3507,7 +3506,7 @@ SOFTWARE.
3507
3506
 
3508
3507
  ### jsdoc
3509
3508
 
3510
- This product includes source derived from [jsdoc](https://github.com/jsdoc/jsdoc) ([v4.0.4](https://github.com/jsdoc/jsdoc/tree/v4.0.4)), distributed under the [Apache-2.0 License](https://github.com/jsdoc/jsdoc/blob/v4.0.4/LICENSE.md):
3509
+ This product includes source derived from [jsdoc](https://github.com/jsdoc/jsdoc) ([v4.0.3](https://github.com/jsdoc/jsdoc/tree/v4.0.3)), distributed under the [Apache-2.0 License](https://github.com/jsdoc/jsdoc/blob/v4.0.3/LICENSE.md):
3511
3510
 
3512
3511
  ```
3513
3512
  # License
@@ -4002,7 +4001,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4002
4001
 
4003
4002
  ### self-cert
4004
4003
 
4005
- 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):
4004
+ This product includes source derived from [self-cert](https://github.com/jsumners/self-cert) ([v2.0.0](https://github.com/jsumners/self-cert/tree/v2.0.0)), distributed under the [MIT License](https://github.com/jsumners/self-cert/blob/v2.0.0/Readme.md):
4006
4005
 
4007
4006
  ```
4008
4007
  MIT License
@@ -4132,34 +4131,6 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4132
4131
 
4133
4132
  ```
4134
4133
 
4135
- ### temp
4136
-
4137
- This product includes source derived from [temp](https://github.com/bruce/node-temp) ([v0.8.4](https://github.com/bruce/node-temp/tree/v0.8.4)), distributed under the [MIT License](https://github.com/bruce/node-temp/blob/v0.8.4/LICENSE):
4138
-
4139
- ```
4140
- The MIT License (MIT)
4141
-
4142
- Copyright (c) 2010-2014 Bruce Williams
4143
-
4144
- Permission is hereby granted, free of charge, to any person obtaining a copy of
4145
- this software and associated documentation files (the "Software"), to deal in
4146
- the Software without restriction, including without limitation the rights to
4147
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
4148
- the Software, and to permit persons to whom the Software is furnished to do so,
4149
- subject to the following conditions:
4150
-
4151
- The above copyright notice and this permission notice shall be included in all
4152
- copies or substantial portions of the Software.
4153
-
4154
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4155
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
4156
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
4157
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
4158
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
4159
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4160
-
4161
- ```
4162
-
4163
4134
 
4164
4135
  ## optionalDependencies
4165
4136
 
package/lib/agent.js CHANGED
@@ -40,6 +40,7 @@ const {
40
40
  } = require('./util/attributes')
41
41
  const synthetics = require('./synthetics')
42
42
  const Harvester = require('./harvester')
43
+ const { createFeatureUsageMetrics } = require('./util/application-logging')
43
44
 
44
45
  // Map of valid states to whether or not data collection is valid
45
46
  const STATES = {
@@ -405,7 +406,7 @@ Agent.prototype.startStreaming = function startStreaming() {
405
406
  */
406
407
  Agent.prototype.onConnect = function onConnect(shouldImmediatelyHarvest, callback) {
407
408
  this.harvester.update(this.config)
408
- generateLoggingSupportMetrics(this)
409
+ createFeatureUsageMetrics(this)
409
410
 
410
411
  if (this.config.certificates && this.config.certificates.length > 0) {
411
412
  this.metrics.getOrCreateMetric(NAMES.FEATURES.CERTIFICATES).incrementCallCount()
@@ -821,6 +822,8 @@ Agent.prototype._listenForConfigChanges = function _listenForConfigChanges() {
821
822
  * This method returns an object with the following keys/data:
822
823
  * - `trace.id`: The current trace ID
823
824
  * - `span.id`: The current span ID
825
+ *
826
+ * If `excludeServiceLinks` is false it will also include the following:
824
827
  * - `entity.name`: The application name specified in the connect request as
825
828
  * app_name. If multiple application names are specified this will only be
826
829
  * the first name
@@ -830,17 +833,14 @@ Agent.prototype._listenForConfigChanges = function _listenForConfigChanges() {
830
833
  * utilization.full_hostname. If utilization.full_hostname is null or empty,
831
834
  * this will be the hostname specified in the connect request as host.
832
835
  *
836
+ * @param {boolean} excludeServiceLinks flag to indicate if you should include `entity.guid`, `entity.type`, `entity.name` and `hostname` from linking metadata
833
837
  * @returns {object} The LinkingMetadata object with the data above
834
838
  */
835
- Agent.prototype.getLinkingMetadata = function getLinkingMetadata() {
839
+ Agent.prototype.getLinkingMetadata = function getLinkingMetadata(excludeServiceLinks = false) {
836
840
  const segment = this.tracer.getSegment()
837
841
  const config = this.config
838
842
 
839
- const linkingMetadata = {
840
- 'entity.name': config.applications()[0],
841
- 'entity.type': 'SERVICE',
842
- 'hostname': config.getHostnameSafe()
843
- }
843
+ const linkingMetadata = {}
844
844
 
845
845
  if (config.distributed_tracing.enabled && segment) {
846
846
  linkingMetadata['trace.id'] = segment.transaction.traceId
@@ -852,10 +852,37 @@ Agent.prototype.getLinkingMetadata = function getLinkingMetadata() {
852
852
  logger.debug('getLinkingMetadata with no active transaction')
853
853
  }
854
854
 
855
+ if (!excludeServiceLinks) {
856
+ this.getServiceLinkingMetadata(linkingMetadata)
857
+ }
858
+
859
+ return linkingMetadata
860
+ }
861
+
862
+ /**
863
+ * This methods returns an object with the following keys/data:
864
+ * - `entity.name`: The application name specified in the connect request as
865
+ * app_name. If multiple application names are specified this will only be
866
+ * the first name
867
+ * - `entity.type`: The string "SERVICE"
868
+ * - `entity.guid`: The entity ID returned in the connect reply as entity_guid
869
+ * - `hostname`: The hostname as specified in the connect request as
870
+ * utilization.full_hostname. If utilization.full_hostname is null or empty,
871
+ * this will be the hostname specified in the connect request as host.
872
+ *
873
+ * @param {object} linkingMetadata object to add service linking keys
874
+ * @returns {object} with service linking metadata
875
+ */
876
+ Agent.prototype.getServiceLinkingMetadata = function getServiceLinkingMetadata(
877
+ linkingMetadata = {}
878
+ ) {
879
+ const config = this.config
855
880
  if (config.entity_guid) {
856
881
  linkingMetadata['entity.guid'] = config.entity_guid
857
882
  }
858
-
883
+ linkingMetadata['entity.name'] = config.applications()[0]
884
+ linkingMetadata['entity.type'] = 'SERVICE'
885
+ linkingMetadata.hostname = config.getHostnameSafe()
859
886
  return linkingMetadata
860
887
  }
861
888
 
@@ -927,23 +954,4 @@ function generateEventHarvestSupportMetrics(agent, harvestConfig) {
927
954
  }
928
955
  }
929
956
 
930
- /**
931
- * Increments the call counts of application logging supportability metrics
932
- * on every connect cycle
933
- *
934
- * @param {object} agent Instantiation of Node.js agent
935
- */
936
- function generateLoggingSupportMetrics(agent) {
937
- const loggingConfig = agent.config.application_logging
938
- const logNames = NAMES.LOGGING
939
-
940
- const configKeys = ['metrics', 'forwarding', 'local_decorating']
941
- configKeys.forEach((configValue) => {
942
- const configFlag =
943
- loggingConfig.enabled && loggingConfig[`${configValue}`].enabled ? 'enabled' : 'disabled'
944
- const metricName = logNames[`${configValue.toUpperCase()}`]
945
- agent.metrics.getOrCreateMetric(`${metricName}${configFlag}`).incrementCallCount()
946
- })
947
- }
948
-
949
957
  module.exports = Agent
@@ -6,6 +6,7 @@
6
6
  'use strict'
7
7
 
8
8
  const logger = require('../logger').child({ component: 'logs_aggregator' })
9
+ const { isLogLabelingEnabled } = require('../../lib/util/application-logging')
9
10
  const EventAggregator = require('./event-aggregator')
10
11
 
11
12
  const NAMES = require('../metrics/names')
@@ -56,7 +57,18 @@ class LogAggregator extends EventAggregator {
56
57
  return
57
58
  }
58
59
 
59
- return [{ logs: formattedLogs }]
60
+ let commonAttrs = this.agent.getServiceLinkingMetadata()
61
+
62
+ if (isLogLabelingEnabled(this.agent.config)) {
63
+ commonAttrs = { ...commonAttrs, ...this.agent.config.loggingLabels }
64
+ }
65
+
66
+ return [
67
+ {
68
+ common: { attributes: commonAttrs },
69
+ logs: formattedLogs
70
+ }
71
+ ]
60
72
  }
61
73
 
62
74
  add(logLine) {
@@ -8,7 +8,6 @@
8
8
  const fetchSystemInfo = require('../system-info')
9
9
  const defaultLogger = require('../logger').child({ component: 'facts' })
10
10
  const os = require('os')
11
- const parseLabels = require('../util/label-parser')
12
11
 
13
12
  module.exports = facts
14
13
 
@@ -49,7 +48,7 @@ async function facts(agent, callback, { logger = defaultLogger } = {}) {
49
48
  environment: environment,
50
49
  settings: agent.config.publicSettings(),
51
50
  high_security: agent.config.high_security,
52
- labels: parseLabels(agent.config.labels),
51
+ labels: agent.config.parsedLabels,
53
52
  metadata: Object.keys(process.env).reduce((obj, key) => {
54
53
  if (key.startsWith('NEW_RELIC_METADATA_')) {
55
54
  obj[key] = process.env[key]
@@ -1185,6 +1185,22 @@ defaultConfig.definition = () => ({
1185
1185
  max_samples_stored: {
1186
1186
  formatter: int,
1187
1187
  default: 10000
1188
+ },
1189
+ labels: {
1190
+ /**
1191
+ * If `true`, the agent attaches labels to log records.
1192
+ */
1193
+ enabled: {
1194
+ formatter: boolean,
1195
+ default: false
1196
+ },
1197
+ /**
1198
+ * A case-insensitive array containing the labels to exclude from log records.
1199
+ */
1200
+ exclude: {
1201
+ formatter: array,
1202
+ default: []
1203
+ }
1188
1204
  }
1189
1205
  },
1190
1206
  metrics: {
@@ -24,6 +24,7 @@ const harvestConfigValidator = require('./harvest-config-validator')
24
24
  const mergeServerConfig = new MergeServerConfig()
25
25
  const { boolean: isTruthular } = require('./formatters')
26
26
  const configDefinition = definition()
27
+ const parseLabels = require('../util/label-parser')
27
28
 
28
29
  /**
29
30
  * CONSTANTS -- we gotta lotta 'em
@@ -195,9 +196,38 @@ function Config(config) {
195
196
 
196
197
  // 9. Set instance attribute filter using updated context
197
198
  this.attributeFilter = new AttributeFilter(this)
199
+
200
+ // 10. Setup labels for both `collector/facts` and application logging
201
+ this.parsedLabels = parseLabels(this.labels, logger)
202
+ this.loggingLabels = this._setApplicationLoggingLabels()
198
203
  }
199
204
  util.inherits(Config, EventEmitter)
200
205
 
206
+ /**
207
+ * Compares the labels list to the application logging excluded label list and removes any labels that need to be excluded.
208
+ * Then prefixing each label with "tags."
209
+ *
210
+ * assigns labels to `config.loggingLabels`
211
+ */
212
+ Config.prototype._setApplicationLoggingLabels = function setApplicationLoggingLabels() {
213
+ if (this.application_logging.forwarding.labels.enabled === false) {
214
+ return
215
+ }
216
+
217
+ this.application_logging.forwarding.labels.exclude =
218
+ this.application_logging.forwarding.labels.exclude.map((k) => k.toLowerCase())
219
+
220
+ return this.parsedLabels.reduce((filteredLabels, label) => {
221
+ if (
222
+ !this.application_logging.forwarding.labels.exclude.includes(label.label_type.toLowerCase())
223
+ ) {
224
+ filteredLabels[`tags.${label.label_type}`] = label.label_value
225
+ }
226
+
227
+ return filteredLabels
228
+ }, {})
229
+ }
230
+
201
231
  /**
202
232
  * Because this module and logger depend on each other, the logger needs
203
233
  * a way to inject the actual logger instance once it's constructed.
@@ -11,63 +11,116 @@ const symbols = require('../../symbols')
11
11
  const { QuerySpec } = require('../../shim/specs')
12
12
  const DatastoreParameters = require('../../shim/specs/params/datastore')
13
13
 
14
+ /**
15
+ * Used to instrument `mysql` and `mysql2` packages
16
+ * the `mysql2/promise` instrumentation is below in `promiseInitialize`
17
+ *
18
+ * @param {Shim} shim instance of shim
19
+ * @param {object} mysql package to instrument
20
+ */
14
21
  function callbackInitialize(shim, mysql) {
15
22
  shim.setDatastore(shim.MYSQL)
16
23
  shim[symbols.wrappedPoolConnection] = false
17
24
 
18
25
  shim.wrapReturn(mysql, 'createConnection', wrapCreateConnection)
19
- function wrapCreateConnection(shim, fn, fnName, connection) {
20
- if (shim[symbols.unwrapConnection]) {
21
- return
22
- }
23
- shim.logger.debug('Wrapping Connection#query')
24
- if (wrapQueryable(shim, connection, false)) {
25
- const connProto = Object.getPrototypeOf(connection)
26
- connProto[symbols.storeDatabase] = true
27
- shim[symbols.unwrapConnection] = true
26
+ shim.wrapReturn(mysql, 'createPool', wrapCreatePool)
27
+ shim.wrapReturn(mysql, 'createPoolCluster', wrapCreatePoolCluster)
28
+ }
29
+
30
+ /**
31
+ * Used to instrument `mysql2/promise`
32
+ *
33
+ * @param {Shim} shim instance of shim
34
+ * @param {object} mysql2 package to instrument
35
+ */
36
+ function promiseInitialize(shim, mysql2) {
37
+ shim.setDatastore(shim.MYSQL)
38
+ shim[symbols.wrappedPoolConnection] = false
39
+ shim.wrap(
40
+ mysql2,
41
+ 'createConnection',
42
+ function wrapPromiseCreateConnection(shim, createConnection) {
43
+ return async function wrappedPromiseCreateConnection() {
44
+ const promiseConnection = await createConnection.apply(this, arguments)
45
+ wrapCreateConnection(
46
+ shim,
47
+ createConnection,
48
+ 'createConnection',
49
+ promiseConnection.connection
50
+ )
51
+ return promiseConnection
52
+ }
28
53
  }
29
- }
54
+ )
30
55
 
31
- shim.wrapReturn(mysql, 'createPool', wrapCreatePool)
32
- function wrapCreatePool(shim, fn, fnName, pool) {
33
- if (shim[symbols.unwrapPool]) {
34
- return
56
+ shim.wrap(mysql2, 'createPool', function wrapPromiseCreatePool(shim, createPool) {
57
+ return async function wrappedPromiseCreatePool() {
58
+ const promisePool = await createPool.apply(this, arguments)
59
+ wrapCreatePool(shim, createPool, 'createPool', promisePool.pool)
60
+ return promisePool
35
61
  }
36
- shim.logger.debug('Wrapping Pool#query and Pool#getConnection')
37
- if (wrapQueryable(shim, pool, true) && wrapGetConnection(shim, pool)) {
38
- shim[symbols.unwrapPool] = true
62
+ })
63
+
64
+ shim.wrap(
65
+ mysql2,
66
+ 'createPoolCluster',
67
+ function wrapPromiseCreatePoolCluster(shim, createPoolCluster) {
68
+ return async function wrappedPromiseCreatePoolCluster() {
69
+ const promisePoolCluster = await createPoolCluster.apply(this, arguments)
70
+ wrapCreatePoolCluster(
71
+ shim,
72
+ createPoolCluster,
73
+ 'createPoolCluster',
74
+ promisePoolCluster.poolCluster
75
+ )
76
+ return promisePoolCluster
77
+ }
39
78
  }
79
+ )
80
+ }
81
+
82
+ function wrapCreateConnection(shim, fn, fnName, connection) {
83
+ if (shim[symbols.unwrapConnection]) {
84
+ return
40
85
  }
86
+ shim.logger.debug('Wrapping Connection#query')
87
+ if (wrapQueryable(shim, connection, false)) {
88
+ const connProto = Object.getPrototypeOf(connection)
89
+ connProto[symbols.storeDatabase] = true
90
+ shim[symbols.unwrapConnection] = true
91
+ }
92
+ }
41
93
 
42
- shim.wrapReturn(mysql, 'createPoolCluster', wrapCreatePoolCluster)
43
- function wrapCreatePoolCluster(shim, fn, fnName, poolCluster) {
44
- if (shim[symbols.createPoolCluster]) {
45
- return
46
- }
47
- shim.logger.debug('Wrapping PoolCluster#of')
48
- const proto = Object.getPrototypeOf(poolCluster)
49
- shim.wrapReturn(proto, 'of', wrapPoolClusterOf)
50
- function wrapPoolClusterOf(shim, of, _n, poolNamespace) {
51
- if (poolNamespace[symbols.clusterOf]) {
52
- return
53
- }
94
+ function wrapCreatePool(shim, fn, fnName, pool) {
95
+ if (shim[symbols.unwrapPool]) {
96
+ return
97
+ }
98
+ shim.logger.debug('Wrapping Pool#query and Pool#getConnection')
99
+ if (wrapQueryable(shim, pool, true) && wrapGetConnection(shim, pool)) {
100
+ shim[symbols.unwrapPool] = true
101
+ }
102
+ }
54
103
 
55
- if (wrapGetConnection(shim, poolNamespace) && wrapQueryable(shim, poolNamespace, false)) {
56
- poolNamespace[symbols.clusterOf] = true
57
- }
104
+ function wrapCreatePoolCluster(shim, fn, fnName, poolCluster) {
105
+ if (shim[symbols.createPoolCluster]) {
106
+ return
107
+ }
108
+ shim.logger.debug('Wrapping PoolCluster#of')
109
+ const proto = Object.getPrototypeOf(poolCluster)
110
+ shim.wrapReturn(proto, 'of', wrapPoolClusterOf)
111
+ function wrapPoolClusterOf(shim, of, _n, poolNamespace) {
112
+ if (poolNamespace[symbols.clusterOf]) {
113
+ return
58
114
  }
59
115
 
60
- shim.logger.debug('Wrapping PoolCluster#getConnection')
61
- if (wrapGetConnection(shim, poolCluster)) {
62
- shim[symbols.createPoolCluster] = true
116
+ if (wrapGetConnection(shim, poolNamespace) && wrapQueryable(shim, poolNamespace, false)) {
117
+ poolNamespace[symbols.clusterOf] = true
63
118
  }
64
119
  }
65
- }
66
120
 
67
- function promiseInitialize(shim) {
68
- const callbackAPI = shim.require('./index')
69
- if (callbackAPI && !shim.isWrapped(callbackAPI.createConnection)) {
70
- callbackInitialize(shim, callbackAPI)
121
+ shim.logger.debug('Wrapping PoolCluster#getConnection')
122
+ if (wrapGetConnection(shim, poolCluster)) {
123
+ shim[symbols.createPoolCluster] = true
71
124
  }
72
125
  }
73
126
 
@@ -35,7 +35,7 @@ class NrTransport extends TransportStream {
35
35
  * @param {Function} callback callback to invoke once we are done
36
36
  */
37
37
  log(logLine, callback) {
38
- const metadata = this.agent.getLinkingMetadata()
38
+ const metadata = this.agent.getLinkingMetadata(true)
39
39
  const formattedLine = reformatLogLine(logLine, metadata)
40
40
  this.agent.logs.add(formattedLine)
41
41
  callback()
@@ -45,7 +45,6 @@ module.exports = function instrument(shim, tools) {
45
45
  * @param {object} params.tools exported `pino/lib/tools`
46
46
  */
47
47
  function wrapAsJson({ shim, tools }) {
48
- const symbols = shim.require('./lib/symbols')
49
48
  const { agent } = shim
50
49
  const { config, metrics } = agent
51
50
 
@@ -88,12 +87,10 @@ function wrapAsJson({ shim, tools }) {
88
87
  const logLine = asJson.apply(this, args)
89
88
 
90
89
  if (isLogForwardingEnabled(config, agent)) {
91
- const chindings = this[symbols.chindingsSym]
92
90
  const formatLogLine = reformatLogLine({
93
91
  msg: useMergeObj === true ? args[0].msg : args[1],
94
92
  logLine,
95
93
  agent,
96
- chindings,
97
94
  level,
98
95
  logger: shim.logger
99
96
  })
@@ -114,22 +111,12 @@ function wrapAsJson({ shim, tools }) {
114
111
  * @param {object} params.logLine log line
115
112
  * @param {string} params.msg message of log line
116
113
  * @param {object} params.agent instance of agent
117
- * @param {string} params.chindings serialized string of all common log line data
118
114
  * @param {string} params.level log level
119
115
  * @param {object} params.logger instance of agent logger
120
116
  * @returns {function} wrapped log formatter function
121
117
  */
122
- function reformatLogLine({ logLine, msg, agent, chindings = '', level, logger }) {
123
- const metadata = agent.getLinkingMetadata()
124
-
125
- /**
126
- * pino adds this already for us at times
127
- * since asJson manually constructs the json string,
128
- * it will have hostname twice if we do not delete ours.
129
- */
130
- if (chindings.includes('hostname')) {
131
- delete metadata.hostname
132
- }
118
+ function reformatLogLine({ logLine, msg, agent, level, logger }) {
119
+ const metadata = agent.getLinkingMetadata(true)
133
120
 
134
121
  const agentMeta = Object.assign({}, { timestamp: Date.now() }, metadata)
135
122
  // eslint-disable-next-line eqeqeq
@@ -84,10 +84,19 @@ class BedrockCommand {
84
84
  ) {
85
85
  result = this.#body.prompt
86
86
  } else if (this.isClaude3() === true) {
87
- result = this.#body?.messages?.reduce((acc, curr) => {
88
- acc += curr?.content ?? ''
89
- return acc
90
- }, '')
87
+ const collected = []
88
+ for (const message of this.#body?.messages) {
89
+ if (message?.role === 'assistant') {
90
+ continue
91
+ }
92
+ if (typeof message?.content === 'string') {
93
+ collected.push(message?.content)
94
+ continue
95
+ }
96
+ const mappedMsgObj = message?.content.map((msgContent) => msgContent.text)
97
+ collected.push(mappedMsgObj)
98
+ }
99
+ result = collected.join(' ')
91
100
  }
92
101
  return result
93
102
  }
@@ -337,7 +337,8 @@ const LOGGING = {
337
337
  SENT: `${LOGGING_FORWARDING_PREFIX}/Sent`,
338
338
  FORWARDING: `${LOGGING_FORWARDING_PREFIX}/${NODEJS.PREFIX}`,
339
339
  METRICS: `${SUPPORTABILITY.LOGGING}/Metrics/${NODEJS.PREFIX}`,
340
- LOCAL_DECORATING: `${SUPPORTABILITY.LOGGING}/LocalDecorating/${NODEJS.PREFIX}`
340
+ LOCAL_DECORATING: `${SUPPORTABILITY.LOGGING}/LocalDecorating/${NODEJS.PREFIX}`,
341
+ LABELS: `${SUPPORTABILITY.LOGGING}/Labels/${NODEJS.PREFIX}`
341
342
  }
342
343
 
343
344
  const KAFKA = {
@@ -22,7 +22,7 @@ class LambdaProxyWebRequest {
22
22
  }
23
23
  this.method = ''
24
24
 
25
- if (isGatewayV1Event(event) === true) {
25
+ if (isGatewayV1Event(event) === true || isAlbEvent(event) === true) {
26
26
  this.url.path = event.path
27
27
  this.method = event.httpMethod
28
28
  } else if (isGatewayV2Event(event) === true) {
@@ -54,7 +54,10 @@ class LambdaProxyWebResponse {
54
54
  * @returns {Object<string, string>} The normalized query string map
55
55
  */
56
56
  function normalizeQueryStringParameters(event) {
57
- if (!event.multiValueQueryStringParameters) {
57
+ if (
58
+ !event.multiValueQueryStringParameters ||
59
+ Object.keys(event.multiValueQueryStringParameters).length === 0
60
+ ) {
58
61
  return event.queryStringParameters
59
62
  }
60
63
  return Object.fromEntries(
@@ -107,56 +110,87 @@ function normalizeHeaders(event, lowerCaseKey = false) {
107
110
  * to create a web transaction.
108
111
  */
109
112
  function isLambdaProxyEvent(event) {
110
- return isGatewayV1Event(event) || isGatewayV2Event(event)
113
+ return isGatewayV1Event(event) || isGatewayV2Event(event) || isAlbEvent(event)
114
+ }
115
+
116
+ /**
117
+ * Iterates over the minimum signature properties of an event received by this Lambda function
118
+ * to determine if this request is triggered from a proxy (API Gateway V1, V2, ALB) or some other service.
119
+ * If API Gateway, we need to determine which version: V1 and V2 have a lot of overlap, but some signature
120
+ * differences for which we can test.
121
+ *
122
+ * The test is designed to look only at signature properties used by each version, and returns true with the first
123
+ * top-level match. Each test array has only four elements, and each invocation should incur
124
+ * only five comparisons: one match for its matching type, and four comparisons for the non-matching type.
125
+ *
126
+ * API Gateway v2 HTTP: top-level 'rawPath', 'rawQueryString', 'routeKey'. Possibly 'cookies'
127
+ * API Gateway v1 HTTP: top-level 'httpMethod', 'resource'. Possibly 'multiValueHeaders', 'multiValueQueryStringParameters'
128
+ * API Gateway v1 REST same as HTTP, but without top-level `version`
129
+ * ALB: very similar to API Gateway v1, but requestContext contains an elb property
130
+ *
131
+ * In tests, this set of required API Gateway v1 properties has consistently been delivered in event payloads.
132
+ * Similar tests with API Gateway V2 shows that the cookies property is *only* defined if cookies are present.
133
+ * If `cookies` is present as a top-level property, the event is surely triggered by API Gateway V2. Its absence,
134
+ * though, is *not* a certain indicator of v1. As such, it's the last property considered in our test.
135
+ *
136
+ * @param {object} targetEvent The event to inspect.
137
+ * @param {Array} searchFor An array of keys unique to this proxy type
138
+ * @returns {boolean} Whether this event has matches for the keys we're checking
139
+ */
140
+ function eventHasRequiredKeys(targetEvent, searchFor) {
141
+ const keys = Object.keys(targetEvent)
142
+ for (const el of searchFor) {
143
+ if (keys.indexOf(el) > -1) {
144
+ return true
145
+ }
146
+ }
147
+ return false
111
148
  }
112
149
 
113
150
  // See https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
114
- const restApiV1Keys = [
115
- 'body',
116
- 'headers',
151
+ const requiredHttpApiV1Keys = [
117
152
  'httpMethod',
118
- 'isBase64Encoded',
119
- 'multiValueHeaders',
120
- 'multiValueQueryStringParameters',
121
153
  'path',
122
- 'pathParameters',
123
- 'queryStringParameters',
124
- 'requestContext',
125
154
  'resource',
126
- 'stageVariables'
127
- ].join(',')
155
+ 'multiValueHeaders',
156
+ 'multiValueQueryStringParameters'
157
+ ]
128
158
 
129
159
  // See https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
130
- const httpApiV1Keys = [...restApiV1Keys.split(','), 'version'].join(',')
131
-
132
160
  function isGatewayV1Event(event) {
133
- const keys = Object.keys(event).sort().join(',')
134
- if (keys === httpApiV1Keys && event?.version === '1.0') {
161
+ if (event?.requestContext?.elb !== undefined) {
162
+ return false
163
+ }
164
+ const hasKeys = eventHasRequiredKeys(event, requiredHttpApiV1Keys)
165
+ if (hasKeys && event?.version === '1.0') {
135
166
  return true
136
167
  }
137
-
138
- return keys === restApiV1Keys
168
+ // Rest API doesn't have version, but we can check on the key matching:
169
+ return hasKeys
139
170
  }
140
171
 
141
172
  // See https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
142
- const httpApiV2Keys = [
143
- 'body',
144
- 'cookies',
145
- 'headers',
146
- 'isBase64Encoded',
147
- 'pathParameters',
148
- 'queryStringParameters',
149
- 'rawPath',
150
- 'rawQueryString',
151
- 'requestContext',
152
- 'routeKey',
153
- 'stageVariables',
154
- 'version'
155
- ].join(',')
173
+ const requiredHttpApiV2Keys = ['rawPath', 'rawQueryString', 'routeKey', 'cookies']
156
174
 
157
175
  function isGatewayV2Event(event) {
158
- const keys = Object.keys(event).sort().join(',')
159
- return keys === httpApiV2Keys && event?.version === '2.0'
176
+ if (event?.requestContext?.elb !== undefined) {
177
+ return false
178
+ }
179
+ return eventHasRequiredKeys(event, requiredHttpApiV2Keys) && event?.version === '2.0'
180
+ }
181
+
182
+ /**
183
+ * ALB can act as a proxy for Lambda. Properties have commonalities with API GateWay v1, though ALB-triggered events
184
+ * consistently carry an ARN at requestContext.elb. See
185
+ * https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#receive-event-from-load-balancer
186
+ * and https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html
187
+ *
188
+ * If we check for that property, we can accept variation in other properties.
189
+ * @param {object} event The event property supplied to the Lambda handler
190
+ * @returns {boolean} Whether or not the event was triggered by ALB
191
+ */
192
+ function isAlbEvent(event) {
193
+ return event?.requestContext?.elb !== undefined
160
194
  }
161
195
 
162
196
  /**
@@ -176,5 +210,6 @@ module.exports = {
176
210
  isLambdaProxyEvent,
177
211
  isValidLambdaProxyResponse,
178
212
  isGatewayV1Event,
179
- isGatewayV2Event
213
+ isGatewayV2Event,
214
+ isAlbEvent
180
215
  }
@@ -75,6 +75,16 @@ utils.isLogForwardingEnabled = function isLogForwardingEnabled(config, agent) {
75
75
  )
76
76
  }
77
77
 
78
+ /**
79
+ * Checks if application_logging.forwarding.labels is enabled
80
+ *
81
+ * @param {object} config agent config
82
+ * @returns {boolean} is labeling enabled
83
+ */
84
+ utils.isLogLabelingEnabled = function isLogLabelingEnabled(config) {
85
+ return !!config.application_logging.forwarding.labels.enabled
86
+ }
87
+
78
88
  /**
79
89
  * Increments both `Logging/lines` and `Logging/lines/<level>` call count
80
90
  *
@@ -108,3 +118,51 @@ function getLogLevel(level) {
108
118
  }
109
119
  return logLevel
110
120
  }
121
+
122
+ /**
123
+ * Increments the enabled/disabled metrics for the top line application logging features:
124
+ * 1. Supportability/Logging/Metrics/Nodejs/<enabled|disabled>
125
+ * 2. Supportability/Logging/Forwarding/Nodejs/<enabled|disabled>
126
+ * 3. Supportability/Logging/LocalDecorating/Nodejs/<enabled|disabled>
127
+ * 4. Supportability/Logging/Labels/Nodejs/<enabled|disabled>
128
+ *
129
+ * Run in `agent.onConnect`
130
+ *
131
+ * @param {Agent} agent instance
132
+ */
133
+ utils.createFeatureUsageMetrics = function createFeatureUsageMetrics(agent) {
134
+ const { config, metrics } = agent
135
+ const loggingConfig = config.application_logging.enabled
136
+ metrics
137
+ .getOrCreateMetric(
138
+ `${LOGGING.METRICS}${
139
+ loggingConfig && config.application_logging.metrics.enabled ? 'enabled' : 'disabled'
140
+ }`
141
+ )
142
+ .incrementCallCount()
143
+ metrics
144
+ .getOrCreateMetric(
145
+ `${LOGGING.FORWARDING}${
146
+ loggingConfig && config.application_logging.forwarding.enabled ? 'enabled' : 'disabled'
147
+ }`
148
+ )
149
+ .incrementCallCount()
150
+ metrics
151
+ .getOrCreateMetric(
152
+ `${LOGGING.LOCAL_DECORATING}${
153
+ loggingConfig && config.application_logging.local_decorating.enabled
154
+ ? 'enabled'
155
+ : 'disabled'
156
+ }`
157
+ )
158
+ .incrementCallCount()
159
+ metrics
160
+ .getOrCreateMetric(
161
+ `${LOGGING.LABELS}${
162
+ loggingConfig && config.application_logging.forwarding.labels.enabled
163
+ ? 'enabled'
164
+ : 'disabled'
165
+ }`
166
+ )
167
+ .incrementCallCount()
168
+ }
@@ -11,10 +11,11 @@ module.exports.fromMap = fromMap
11
11
 
12
12
  // this creates a copy of trim that can be used with map
13
13
  const trim = Function.prototype.call.bind(String.prototype.trim)
14
- const logger = require('../logger').child({ component: 'label-parser' })
15
14
  const stringify = require('json-stringify-safe')
16
15
 
17
- function parse(labels) {
16
+ // pass in parent logger to avoid circular deps
17
+ function parse(labels, parentLogger) {
18
+ const logger = parentLogger.child({ component: 'label-parser' })
18
19
  let results
19
20
 
20
21
  if (!labels) {
@@ -25,8 +26,8 @@ function parse(labels) {
25
26
  results = fromMap(labels)
26
27
  }
27
28
 
28
- results.warnings.forEach(function logWarnings(messaage) {
29
- logger.warn(messaage)
29
+ results.warnings.forEach(function logWarnings(message) {
30
+ logger.warn(message)
30
31
  })
31
32
 
32
33
  return results.labels
@@ -106,11 +107,11 @@ function fromMap(map) {
106
107
  try {
107
108
  warnings.unshift('Partially Invalid Label Setting: ' + stringify(map))
108
109
  } catch (err) {
109
- logger.debug(err, 'Failed to stringify labels')
110
+ warnings.unshift('Failed to stringify labels: ' + err.message)
110
111
  }
111
112
  }
112
113
 
113
- return { labels: labels, warnings: warnings }
114
+ return { labels, warnings }
114
115
  }
115
116
 
116
117
  function truncate(str, max) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newrelic",
3
- "version": "12.7.0",
3
+ "version": "12.8.1",
4
4
  "author": "New Relic Node.js agent team <nodejs@newrelic.com>",
5
5
  "license": "Apache-2.0",
6
6
  "contributors": [
@@ -229,7 +229,7 @@
229
229
  "ajv": "^6.12.6",
230
230
  "async": "^3.2.4",
231
231
  "aws-sdk": "^2.1604.0",
232
- "borp": "^0.18.0",
232
+ "borp": "^0.19.0",
233
233
  "c8": "^8.0.1",
234
234
  "clean-jsdoc-theme": "^4.2.18",
235
235
  "commander": "^7.0.0",
@@ -258,8 +258,7 @@
258
258
  "should": "*",
259
259
  "sinon": "^5.1.1",
260
260
  "superagent": "^9.0.1",
261
- "tap": "^16.3.4",
262
- "temp": "^0.8.1"
261
+ "tap": "^16.3.4"
263
262
  },
264
263
  "repository": {
265
264
  "type": "git",