@envelop/newrelic 5.0.4 → 5.0.5-alpha-20230104113641-ef3d8f5b
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/README.md +5 -5
- package/cjs/index.js +59 -66
- package/esm/index.js +59 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@ Take advantage of Distributed tracing to monitor performance and errors whilst u
|
|
|
6
6
|
Below are some screenshots to show how tracking looks like in New Relic, in these examples all plugin options were set to `true`.
|
|
7
7
|
|
|
8
8
|
Error tracking, operation and resolver views:
|
|
9
|
-

|
|
10
|
+

|
|
11
11
|
|
|
12
12
|
Successful operation tracking, operation plus root-field and sub-field resolvers:
|
|
13
|
-

|
|
14
|
+

|
|
15
|
+

|
|
16
16
|
|
|
17
17
|
## Getting Started
|
|
18
18
|
|
package/cjs/index.js
CHANGED
|
@@ -1,32 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
3
|
exports.useNewRelic = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
27
5
|
const core_1 = require("@envelop/core");
|
|
28
6
|
const on_resolve_1 = require("@envelop/on-resolve");
|
|
29
7
|
const graphql_1 = require("graphql");
|
|
8
|
+
const newrelic_1 = tslib_1.__importDefault(require("newrelic"));
|
|
30
9
|
var AttributeName;
|
|
31
10
|
(function (AttributeName) {
|
|
32
11
|
AttributeName["COMPONENT_NAME"] = "Envelop_NewRelic_Plugin";
|
|
@@ -58,29 +37,23 @@ const useNewRelic = (rawOptions) => {
|
|
|
58
37
|
};
|
|
59
38
|
options.isExecuteVariablesRegex = options.includeExecuteVariables instanceof RegExp;
|
|
60
39
|
options.isResolverArgsRegex = options.includeResolverArgs instanceof RegExp;
|
|
61
|
-
const instrumentationApi
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
});
|
|
71
|
-
const
|
|
72
|
-
const childLogger = logger.child({ component: AttributeName.COMPONENT_NAME });
|
|
73
|
-
childLogger.info(`${AttributeName.COMPONENT_NAME} registered`);
|
|
74
|
-
return childLogger;
|
|
75
|
-
});
|
|
40
|
+
const instrumentationApi = newrelic_1.default?.shim;
|
|
41
|
+
if (!instrumentationApi?.agent) {
|
|
42
|
+
console.warn('Agent unavailable. Please check your New Relic Agent configuration and ensure New Relic is enabled.');
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
instrumentationApi.agent.metrics
|
|
46
|
+
.getOrCreateMetric(`Supportability/ExternalModules/${AttributeName.COMPONENT_NAME}`)
|
|
47
|
+
.incrementCallCount();
|
|
48
|
+
const logger = instrumentationApi.logger.child({ component: AttributeName.COMPONENT_NAME });
|
|
49
|
+
logger.info(`${AttributeName.COMPONENT_NAME} registered`);
|
|
50
|
+
const documentSourceMap = new WeakMap();
|
|
76
51
|
return {
|
|
77
52
|
onPluginInit({ addPlugin }) {
|
|
78
53
|
if (options.trackResolvers) {
|
|
79
|
-
addPlugin((0, on_resolve_1.useOnResolve)(
|
|
80
|
-
const instrumentationApi = await instrumentationApi$;
|
|
54
|
+
addPlugin((0, on_resolve_1.useOnResolve)(({ args: resolversArgs, info }) => {
|
|
81
55
|
const transactionNameState = instrumentationApi.agent.tracer.getTransaction().nameState;
|
|
82
56
|
const delimiter = transactionNameState.delimiter;
|
|
83
|
-
const logger = await logger$;
|
|
84
57
|
const { returnType, path, parentType } = info;
|
|
85
58
|
const formattedPath = flattenPath(path, delimiter);
|
|
86
59
|
const currentSegment = instrumentationApi.getActiveSegment();
|
|
@@ -113,51 +86,71 @@ const useNewRelic = (rawOptions) => {
|
|
|
113
86
|
}));
|
|
114
87
|
}
|
|
115
88
|
},
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
89
|
+
onParse({ params: { source } }) {
|
|
90
|
+
return ({ result }) => {
|
|
91
|
+
if (options.includeOperationDocument) {
|
|
92
|
+
const key = source instanceof graphql_1.Source ? source.body : source;
|
|
93
|
+
if (!result || result instanceof Error)
|
|
94
|
+
return;
|
|
95
|
+
documentSourceMap.set(result, key);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
onExecute({ args }) {
|
|
100
|
+
const rootOperation = (0, graphql_1.getOperationAST)(args.document, args.operationName);
|
|
101
|
+
if (!rootOperation) {
|
|
102
|
+
logger.trace('No root operation found. Not recording transaction.');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
124
105
|
const operationType = rootOperation.operation;
|
|
125
|
-
const document = (0, graphql_1.print)(args.document);
|
|
126
106
|
const operationName = options.extractOperationName?.(args.contextValue) ||
|
|
127
107
|
args.operationName ||
|
|
128
108
|
rootOperation.name?.value ||
|
|
129
109
|
AttributeName.ANONYMOUS_OPERATION;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
110
|
+
const transaction = instrumentationApi.agent.tracer.getTransaction();
|
|
111
|
+
const transactionNameState = transaction?.nameState;
|
|
112
|
+
if (transactionNameState) {
|
|
113
|
+
const delimiter = transactionNameState.delimiter || '/';
|
|
114
|
+
let rootFields = null;
|
|
115
|
+
if (options.rootFieldsNaming) {
|
|
116
|
+
const fieldNodes = rootOperation.selectionSet.selections.filter(selectionNode => selectionNode.kind === graphql_1.Kind.FIELD);
|
|
117
|
+
rootFields = fieldNodes.map(fieldNode => fieldNode.name.value);
|
|
118
|
+
}
|
|
119
|
+
const operationType = rootOperation.operation;
|
|
120
|
+
const operationName = options.extractOperationName?.(args.contextValue) ||
|
|
121
|
+
args.operationName ||
|
|
122
|
+
rootOperation.name?.value ||
|
|
123
|
+
AttributeName.ANONYMOUS_OPERATION;
|
|
124
|
+
transactionNameState.setName(transactionNameState.prefix, transactionNameState.verb, delimiter, operationType + delimiter + operationName + (rootFields ? delimiter + rootFields.join('&') : ''));
|
|
134
125
|
}
|
|
135
|
-
|
|
136
|
-
spanContext
|
|
137
|
-
spanContext
|
|
126
|
+
const spanContext = instrumentationApi.agent.tracer.getSpanContext();
|
|
127
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_OPERATION_NAME, operationName);
|
|
128
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_OPERATION_TYPE, operationType);
|
|
138
129
|
options.includeOperationDocument &&
|
|
139
|
-
spanContext
|
|
130
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_OPERATION_DOCUMENT, documentSourceMap.get(args.document) ?? (0, graphql_1.print)(args.document));
|
|
140
131
|
if (options.includeExecuteVariables) {
|
|
141
132
|
const rawVariables = args.variableValues || {};
|
|
142
133
|
const executeVariablesToTrack = options.isExecuteVariablesRegex
|
|
143
134
|
? filterPropertiesByRegex(rawVariables, options.includeExecuteVariables)
|
|
144
135
|
: rawVariables;
|
|
145
|
-
spanContext
|
|
136
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_VARIABLES, JSON.stringify(executeVariablesToTrack));
|
|
146
137
|
}
|
|
147
138
|
const operationSegment = instrumentationApi.getActiveSegment();
|
|
148
139
|
return {
|
|
149
140
|
onExecuteDone({ result }) {
|
|
150
141
|
const sendResult = (singularResult) => {
|
|
151
142
|
if (singularResult.data && options.includeRawResult) {
|
|
152
|
-
spanContext
|
|
143
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_RESULT, JSON.stringify(singularResult));
|
|
153
144
|
}
|
|
154
145
|
if (singularResult.errors && singularResult.errors.length > 0) {
|
|
155
146
|
const agent = instrumentationApi.agent;
|
|
156
147
|
const transaction = instrumentationApi.tracer.getTransaction();
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
148
|
+
if (transaction) {
|
|
149
|
+
for (const error of singularResult.errors) {
|
|
150
|
+
if (options.skipError?.(error))
|
|
151
|
+
continue;
|
|
152
|
+
agent.errors.add(transaction, JSON.stringify(error));
|
|
153
|
+
}
|
|
161
154
|
}
|
|
162
155
|
}
|
|
163
156
|
};
|
|
@@ -167,12 +160,12 @@ const useNewRelic = (rawOptions) => {
|
|
|
167
160
|
sendResult(singularResult);
|
|
168
161
|
},
|
|
169
162
|
onEnd: () => {
|
|
170
|
-
operationSegment
|
|
163
|
+
operationSegment?.end();
|
|
171
164
|
},
|
|
172
165
|
};
|
|
173
166
|
}
|
|
174
167
|
sendResult(result);
|
|
175
|
-
operationSegment
|
|
168
|
+
operationSegment?.end();
|
|
176
169
|
return {};
|
|
177
170
|
},
|
|
178
171
|
};
|
package/esm/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isAsyncIterable } from '@envelop/core';
|
|
2
2
|
import { useOnResolve } from '@envelop/on-resolve';
|
|
3
|
-
import { print, Kind } from 'graphql';
|
|
3
|
+
import { print, Kind, Source, getOperationAST } from 'graphql';
|
|
4
|
+
import newRelic from 'newrelic';
|
|
4
5
|
var AttributeName;
|
|
5
6
|
(function (AttributeName) {
|
|
6
7
|
AttributeName["COMPONENT_NAME"] = "Envelop_NewRelic_Plugin";
|
|
@@ -32,30 +33,23 @@ export const useNewRelic = (rawOptions) => {
|
|
|
32
33
|
};
|
|
33
34
|
options.isExecuteVariablesRegex = options.includeExecuteVariables instanceof RegExp;
|
|
34
35
|
options.isResolverArgsRegex = options.includeResolverArgs instanceof RegExp;
|
|
35
|
-
const instrumentationApi
|
|
36
|
-
|
|
37
|
-
.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const logger$ = instrumentationApi$.then(({ logger }) => {
|
|
47
|
-
const childLogger = logger.child({ component: AttributeName.COMPONENT_NAME });
|
|
48
|
-
childLogger.info(`${AttributeName.COMPONENT_NAME} registered`);
|
|
49
|
-
return childLogger;
|
|
50
|
-
});
|
|
36
|
+
const instrumentationApi = newRelic?.shim;
|
|
37
|
+
if (!instrumentationApi?.agent) {
|
|
38
|
+
console.warn('Agent unavailable. Please check your New Relic Agent configuration and ensure New Relic is enabled.');
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
instrumentationApi.agent.metrics
|
|
42
|
+
.getOrCreateMetric(`Supportability/ExternalModules/${AttributeName.COMPONENT_NAME}`)
|
|
43
|
+
.incrementCallCount();
|
|
44
|
+
const logger = instrumentationApi.logger.child({ component: AttributeName.COMPONENT_NAME });
|
|
45
|
+
logger.info(`${AttributeName.COMPONENT_NAME} registered`);
|
|
46
|
+
const documentSourceMap = new WeakMap();
|
|
51
47
|
return {
|
|
52
48
|
onPluginInit({ addPlugin }) {
|
|
53
49
|
if (options.trackResolvers) {
|
|
54
|
-
addPlugin(useOnResolve(
|
|
55
|
-
const instrumentationApi = await instrumentationApi$;
|
|
50
|
+
addPlugin(useOnResolve(({ args: resolversArgs, info }) => {
|
|
56
51
|
const transactionNameState = instrumentationApi.agent.tracer.getTransaction().nameState;
|
|
57
52
|
const delimiter = transactionNameState.delimiter;
|
|
58
|
-
const logger = await logger$;
|
|
59
53
|
const { returnType, path, parentType } = info;
|
|
60
54
|
const formattedPath = flattenPath(path, delimiter);
|
|
61
55
|
const currentSegment = instrumentationApi.getActiveSegment();
|
|
@@ -88,51 +82,71 @@ export const useNewRelic = (rawOptions) => {
|
|
|
88
82
|
}));
|
|
89
83
|
}
|
|
90
84
|
},
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
85
|
+
onParse({ params: { source } }) {
|
|
86
|
+
return ({ result }) => {
|
|
87
|
+
if (options.includeOperationDocument) {
|
|
88
|
+
const key = source instanceof Source ? source.body : source;
|
|
89
|
+
if (!result || result instanceof Error)
|
|
90
|
+
return;
|
|
91
|
+
documentSourceMap.set(result, key);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
onExecute({ args }) {
|
|
96
|
+
const rootOperation = getOperationAST(args.document, args.operationName);
|
|
97
|
+
if (!rootOperation) {
|
|
98
|
+
logger.trace('No root operation found. Not recording transaction.');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
99
101
|
const operationType = rootOperation.operation;
|
|
100
|
-
const document = print(args.document);
|
|
101
102
|
const operationName = options.extractOperationName?.(args.contextValue) ||
|
|
102
103
|
args.operationName ||
|
|
103
104
|
rootOperation.name?.value ||
|
|
104
105
|
AttributeName.ANONYMOUS_OPERATION;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
const transaction = instrumentationApi.agent.tracer.getTransaction();
|
|
107
|
+
const transactionNameState = transaction?.nameState;
|
|
108
|
+
if (transactionNameState) {
|
|
109
|
+
const delimiter = transactionNameState.delimiter || '/';
|
|
110
|
+
let rootFields = null;
|
|
111
|
+
if (options.rootFieldsNaming) {
|
|
112
|
+
const fieldNodes = rootOperation.selectionSet.selections.filter(selectionNode => selectionNode.kind === Kind.FIELD);
|
|
113
|
+
rootFields = fieldNodes.map(fieldNode => fieldNode.name.value);
|
|
114
|
+
}
|
|
115
|
+
const operationType = rootOperation.operation;
|
|
116
|
+
const operationName = options.extractOperationName?.(args.contextValue) ||
|
|
117
|
+
args.operationName ||
|
|
118
|
+
rootOperation.name?.value ||
|
|
119
|
+
AttributeName.ANONYMOUS_OPERATION;
|
|
120
|
+
transactionNameState.setName(transactionNameState.prefix, transactionNameState.verb, delimiter, operationType + delimiter + operationName + (rootFields ? delimiter + rootFields.join('&') : ''));
|
|
109
121
|
}
|
|
110
|
-
|
|
111
|
-
spanContext
|
|
112
|
-
spanContext
|
|
122
|
+
const spanContext = instrumentationApi.agent.tracer.getSpanContext();
|
|
123
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_OPERATION_NAME, operationName);
|
|
124
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_OPERATION_TYPE, operationType);
|
|
113
125
|
options.includeOperationDocument &&
|
|
114
|
-
spanContext
|
|
126
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_OPERATION_DOCUMENT, documentSourceMap.get(args.document) ?? print(args.document));
|
|
115
127
|
if (options.includeExecuteVariables) {
|
|
116
128
|
const rawVariables = args.variableValues || {};
|
|
117
129
|
const executeVariablesToTrack = options.isExecuteVariablesRegex
|
|
118
130
|
? filterPropertiesByRegex(rawVariables, options.includeExecuteVariables)
|
|
119
131
|
: rawVariables;
|
|
120
|
-
spanContext
|
|
132
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_VARIABLES, JSON.stringify(executeVariablesToTrack));
|
|
121
133
|
}
|
|
122
134
|
const operationSegment = instrumentationApi.getActiveSegment();
|
|
123
135
|
return {
|
|
124
136
|
onExecuteDone({ result }) {
|
|
125
137
|
const sendResult = (singularResult) => {
|
|
126
138
|
if (singularResult.data && options.includeRawResult) {
|
|
127
|
-
spanContext
|
|
139
|
+
spanContext?.addCustomAttribute(AttributeName.EXECUTION_RESULT, JSON.stringify(singularResult));
|
|
128
140
|
}
|
|
129
141
|
if (singularResult.errors && singularResult.errors.length > 0) {
|
|
130
142
|
const agent = instrumentationApi.agent;
|
|
131
143
|
const transaction = instrumentationApi.tracer.getTransaction();
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
144
|
+
if (transaction) {
|
|
145
|
+
for (const error of singularResult.errors) {
|
|
146
|
+
if (options.skipError?.(error))
|
|
147
|
+
continue;
|
|
148
|
+
agent.errors.add(transaction, JSON.stringify(error));
|
|
149
|
+
}
|
|
136
150
|
}
|
|
137
151
|
}
|
|
138
152
|
};
|
|
@@ -142,12 +156,12 @@ export const useNewRelic = (rawOptions) => {
|
|
|
142
156
|
sendResult(singularResult);
|
|
143
157
|
},
|
|
144
158
|
onEnd: () => {
|
|
145
|
-
operationSegment
|
|
159
|
+
operationSegment?.end();
|
|
146
160
|
},
|
|
147
161
|
};
|
|
148
162
|
}
|
|
149
163
|
sendResult(result);
|
|
150
|
-
operationSegment
|
|
164
|
+
operationSegment?.end();
|
|
151
165
|
return {};
|
|
152
166
|
},
|
|
153
167
|
};
|