appdynamics 24.9.0 → 24.12.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/appdynamics_version.json +3 -3
- package/lib/core/agent.js +7 -3
- package/lib/core/opentelemetry-tracer.js +17 -6
- package/lib/libagent/libagent-connector.js +33 -0
- package/lib/libagent/transaction-sender.js +26 -3
- package/lib/probes/apollo-entry-probe.js +95 -41
- package/lib/probes/http-common.js +29 -5
- package/lib/probes/http-entry-probe.js +4 -3
- package/lib/probes/http-probe.js +14 -2
- package/lib/probes/mongodb-probe.js +9 -9
- package/lib/profiler/profiler.js +55 -0
- package/package.json +4 -4
- package/packageBck.json +4 -4
package/appdynamics_version.json
CHANGED
package/lib/core/agent.js
CHANGED
|
@@ -189,7 +189,7 @@ Agent.prototype.isMainThread = function () {
|
|
|
189
189
|
return isMainThread;
|
|
190
190
|
};
|
|
191
191
|
|
|
192
|
-
function setMetadataFile(instrumentedStatus) {
|
|
192
|
+
function setMetadataFile(agent, instrumentedStatus) {
|
|
193
193
|
const filePath = process.env.APPDYNAMICS_AGENT_DIR || '/tmp/appd';
|
|
194
194
|
const fileName = path.join(filePath, 'app-metadata.json');
|
|
195
195
|
|
|
@@ -198,7 +198,7 @@ function setMetadataFile(instrumentedStatus) {
|
|
|
198
198
|
const content = JSON.stringify({ instrumented: instrumentedStatus });
|
|
199
199
|
fs.writeFileSync(fileName, content);
|
|
200
200
|
} catch (err) {
|
|
201
|
-
|
|
201
|
+
agent.logger.error(
|
|
202
202
|
`Unable to write the file app-metadata.json to path ${filePath} \n`,
|
|
203
203
|
err
|
|
204
204
|
);
|
|
@@ -240,7 +240,7 @@ Agent.prototype.init = function (opts) {
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
|
|
243
|
-
self.libagentConnector.subscribeToIsEnabled((isEnabled) => setMetadataFile(isEnabled));
|
|
243
|
+
self.libagentConnector.subscribeToIsEnabled((isEnabled) => setMetadataFile(self, isEnabled));
|
|
244
244
|
|
|
245
245
|
self.precompiled = opts.precompiled === undefined || opts.precompiled;
|
|
246
246
|
|
|
@@ -731,3 +731,7 @@ var AppDynamics = function () {
|
|
|
731
731
|
AppDynamics.Agent = Agent;
|
|
732
732
|
|
|
733
733
|
exports = module.exports = new AppDynamics();
|
|
734
|
+
|
|
735
|
+
// export for testing
|
|
736
|
+
exports._setMetadataFile = setMetadataFile;
|
|
737
|
+
|
|
@@ -6,7 +6,7 @@ const { BatchSpanProcessor, BasicTracerProvider } = require('@opentelemetry/sdk-
|
|
|
6
6
|
const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-proto");
|
|
7
7
|
const { AsyncHooksContextManager, AsyncLocalStorageContextManager } = require("@opentelemetry/context-async-hooks");
|
|
8
8
|
const { ParentBasedSampler, AlwaysOnSampler, TraceIdRatioBasedSampler } = require("@opentelemetry/core");
|
|
9
|
-
const { Resource } = require('@opentelemetry/resources');
|
|
9
|
+
const { Resource, envDetectorSync, processDetectorSync, hostDetectorSync } = require('@opentelemetry/resources');
|
|
10
10
|
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
|
|
11
11
|
const AppdynamicsSpanExporter = require('./appdynamics_span_exporter').AppdynamicsSpanExporter;
|
|
12
12
|
const url = require('url');
|
|
@@ -33,15 +33,26 @@ function getSamplerFromConfig(config) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
TracerProvider.prototype.register = function(config) {
|
|
36
|
+
const envResource = envDetectorSync.detect();
|
|
37
|
+
const processResource = processDetectorSync.detect();
|
|
38
|
+
const hostResource = hostDetectorSync.detect();
|
|
39
|
+
|
|
40
|
+
const configResourceAttributes = {
|
|
41
|
+
[SemanticResourceAttributes.SERVICE_NAME]: config.tierName,
|
|
42
|
+
[SemanticResourceAttributes.SERVICE_NAMESPACE]: config.applicationName,
|
|
43
|
+
[SemanticResourceAttributes.CONTAINER_ID]: ""
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const mergedResource = new Resource(configResourceAttributes)
|
|
47
|
+
.merge(envResource)
|
|
48
|
+
.merge(processResource)
|
|
49
|
+
.merge(hostResource);
|
|
50
|
+
|
|
36
51
|
const provider = new BasicTracerProvider({
|
|
37
52
|
sampler: new ParentBasedSampler({
|
|
38
53
|
root: getSamplerFromConfig(config.openTelemetry)
|
|
39
54
|
}),
|
|
40
|
-
resource:
|
|
41
|
-
[SemanticResourceAttributes.SERVICE_NAME]: config.tierName,
|
|
42
|
-
[SemanticResourceAttributes.SERVICE_NAMESPACE]: config.applicationName,
|
|
43
|
-
[SemanticResourceAttributes.CONTAINER_ID]: ""
|
|
44
|
-
}),
|
|
55
|
+
resource: mergedResource,
|
|
45
56
|
});
|
|
46
57
|
|
|
47
58
|
// default collector configuration, can be overridden from agent config
|
|
@@ -174,6 +174,12 @@ LibagentConnector.prototype.init = function () {
|
|
|
174
174
|
|
|
175
175
|
self.agent.transactionSender.isEnabled = true;
|
|
176
176
|
});
|
|
177
|
+
|
|
178
|
+
self.libagent.delegate.on('sepDropped', function (guid) {
|
|
179
|
+
var profiler = self.agent.profiler;
|
|
180
|
+
profiler.sepDropped(guid);
|
|
181
|
+
});
|
|
182
|
+
|
|
177
183
|
self.libagent.delegate.on('transactionDropped', function (guid) {
|
|
178
184
|
var profiler = self.agent.profiler;
|
|
179
185
|
profiler.transactionDropped(guid);
|
|
@@ -229,6 +235,33 @@ LibagentConnector.prototype.stopBusinessTransaction = function (transaction) {
|
|
|
229
235
|
self.libagent.stopBusinessTransaction(transaction.btGuid);
|
|
230
236
|
};
|
|
231
237
|
|
|
238
|
+
LibagentConnector.prototype.startServiceEndpoint = function (entryPointType, request) {
|
|
239
|
+
var self = this;
|
|
240
|
+
return self.libagent.startServiceEndpoint(entryPointType, request);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
LibagentConnector.prototype.stopServiceEndpoint = function (sep) {
|
|
244
|
+
var self = this;
|
|
245
|
+
|
|
246
|
+
if(!self.agent.profiler.isValidSepThreadId(sep.threadId)) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (sep.error) {
|
|
251
|
+
var name = self.protobufModel.extractErrorName(sep.error);
|
|
252
|
+
if (!name) {
|
|
253
|
+
name = "";
|
|
254
|
+
}
|
|
255
|
+
var message = self.protobufModel.extractErrorMessage(sep.error);
|
|
256
|
+
if (!message) {
|
|
257
|
+
message = "";
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
self.libagent.addErrorToEndpoint(sep.sepGuid, name, message);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
self.libagent.stopServiceEndpoint(sep.sepGuid);
|
|
264
|
+
};
|
|
232
265
|
|
|
233
266
|
LibagentConnector.prototype.startExitCall = function (transaction, exitCall) {
|
|
234
267
|
var self = this;
|
|
@@ -22,6 +22,29 @@ TransactionSender.prototype.init = function() {
|
|
|
22
22
|
self.isEnabled = true;
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
self.agent.on("serviceEndpointStart", function(sep, req) {
|
|
26
|
+
if (!self.isEnabled) {
|
|
27
|
+
self.agent.logger.warn('serviceEndpointStart sent without enabled sender');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
var sepData = libagentConnector.startServiceEndpoint('NODEJS_WEB', utility.createBtNamingWrapper(req));
|
|
31
|
+
|
|
32
|
+
if (sepData === undefined || sepData.isExcluded) {
|
|
33
|
+
sep.skip = true;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
sep.skip = false;
|
|
38
|
+
sep.name = sepData.name;
|
|
39
|
+
sep.sepGuid = sepData.sepGuid;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
self.agent.on("serviceEndpointStop", function(sep) {
|
|
43
|
+
if (!self.isEnabled || sep.skip) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
libagentConnector.stopServiceEndpoint(sep);
|
|
47
|
+
});
|
|
25
48
|
|
|
26
49
|
self.agent.on("transactionStarted", function(transaction, req) {
|
|
27
50
|
if (!self.isEnabled) {
|
|
@@ -47,15 +70,15 @@ TransactionSender.prototype.init = function() {
|
|
|
47
70
|
if('singularityheader' in req.headers) {
|
|
48
71
|
corrHeader = req.headers.singularityheader || "";
|
|
49
72
|
} else if(self.agent.tracer && transaction.baggageCorrHeader) {
|
|
50
|
-
/*
|
|
51
|
-
* 1: We append the doNotResolveSubHeader when the upstream is a pure OT service to
|
|
73
|
+
/*
|
|
74
|
+
* 1: We append the doNotResolveSubHeader when the upstream is a pure OT service to
|
|
52
75
|
* prevent resolution to the preceding APPD service
|
|
53
76
|
2: The noTxDetectHeader is treated specially by libagent, so do not append the doNotResolveSubHeader
|
|
54
77
|
in this case
|
|
55
78
|
*/
|
|
56
79
|
const noTxDetectHeader = self.agent.correlation.DISABLE_TRANSACTION_DETECTION + '=true';
|
|
57
80
|
const doNotResolveSubHeader = self.agent.correlation.DONOTRESOLVE + '=true';
|
|
58
|
-
corrHeader = transaction.baggageCorrHeader != noTxDetectHeader ? transaction.baggageCorrHeader + '*' +
|
|
81
|
+
corrHeader = transaction.baggageCorrHeader != noTxDetectHeader ? transaction.baggageCorrHeader + '*' +
|
|
59
82
|
doNotResolveSubHeader : transaction.baggageCorrHeader;
|
|
60
83
|
self.agent.logger.debug(`Using Singularity Header from Opentelemetry Baggage ${corrHeader}`);
|
|
61
84
|
}
|
|
@@ -22,7 +22,22 @@ ApolloEntryProbe.prototype.attach = function (obj, moduleName) {
|
|
|
22
22
|
"createServerInfo",
|
|
23
23
|
(args) => this.addLifeCycleHooks(args)
|
|
24
24
|
);
|
|
25
|
-
} else {
|
|
25
|
+
} else if (moduleName === '@apollo/server') {
|
|
26
|
+
|
|
27
|
+
const originalObject = obj;
|
|
28
|
+
const overriddenObject = {};
|
|
29
|
+
|
|
30
|
+
overriddenObject.ApolloServer = proxyApolloServer(self, originalObject);
|
|
31
|
+
return overriddenObject;
|
|
32
|
+
|
|
33
|
+
} else if(moduleName === '@apollo/server/express4') {
|
|
34
|
+
const originalObject = obj;
|
|
35
|
+
const overriddenObject = {};
|
|
36
|
+
|
|
37
|
+
overriddenObject.expressMiddleware = proxyExpressMiddleware(self, originalObject);
|
|
38
|
+
overriddenObject.__proto__ = originalObject;
|
|
39
|
+
return overriddenObject;
|
|
40
|
+
} else if(moduleName === '@apollo/server/standalone'){
|
|
26
41
|
const originalObject = obj;
|
|
27
42
|
const overriddenObject = {};
|
|
28
43
|
|
|
@@ -80,48 +95,87 @@ ApolloEntryProbe.prototype.addLifeCycleHooks = function (obj) {
|
|
|
80
95
|
];
|
|
81
96
|
};
|
|
82
97
|
|
|
83
|
-
function
|
|
98
|
+
function appDynamicsApolloServerPlugin(self) {
|
|
99
|
+
const plugin = {
|
|
100
|
+
async requestDidStart() {
|
|
101
|
+
return {
|
|
102
|
+
didResolveOperation(requestContext) {
|
|
103
|
+
if(!requestContext.contextValue.gqlReq) {
|
|
104
|
+
requestContext.contextValue.gqlReq = {};
|
|
105
|
+
requestContext.contextValue.gqlRes = {};
|
|
106
|
+
}
|
|
107
|
+
requestContext.contextValue.gqlReq.graphqlop = requestContext.operationName;
|
|
108
|
+
requestContext.contextValue.gqlReq.transactionStarted = true;
|
|
109
|
+
|
|
110
|
+
HttpCommon.startTransactionHandler(
|
|
111
|
+
requestContext.contextValue.gqlReq,
|
|
112
|
+
requestContext.contextValue.gqlRes,
|
|
113
|
+
self.agent
|
|
114
|
+
);
|
|
115
|
+
},
|
|
116
|
+
didEncounterErrors(requestContext) {
|
|
117
|
+
if(!requestContext.contextValue.gqlReq) {
|
|
118
|
+
requestContext.contextValue.gqlReq = {};
|
|
119
|
+
requestContext.contextValue.gqlRes = {};
|
|
120
|
+
}
|
|
121
|
+
requestContext.contextValue.gqlRes.error = requestContext.errors[0];
|
|
122
|
+
if(requestContext.contextValue.gqlReq.transactionStarted) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
HttpCommon.startTransactionHandler(
|
|
126
|
+
requestContext.contextValue.gqlReq,
|
|
127
|
+
requestContext.contextValue.gqlRes,
|
|
128
|
+
self.agent
|
|
129
|
+
);
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
return plugin;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function appDymanicsApolloServerOverriddenOptions(options) {
|
|
138
|
+
const overriddenOptions = options || {};
|
|
139
|
+
|
|
140
|
+
const context = options ? options.context : undefined;
|
|
141
|
+
const overriddenContext = async function (contextParam) {
|
|
142
|
+
const contextValue = context ? await context(contextParam) : {};
|
|
143
|
+
contextParam.req.url = contextParam.req.baseUrl; // For Apollo Server 4
|
|
144
|
+
contextValue.gqlReq = contextParam.req;
|
|
145
|
+
contextValue.gqlRes = contextParam.res;
|
|
146
|
+
return contextValue;
|
|
147
|
+
};
|
|
148
|
+
overriddenOptions.context = overriddenContext;
|
|
149
|
+
return overriddenOptions;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function proxyApolloServer(self, originalObject) {
|
|
153
|
+
const ApolloServer = originalObject.ApolloServer;
|
|
84
154
|
|
|
155
|
+
// Define ApolloServerProxy class
|
|
156
|
+
class ApolloServerProxy extends ApolloServer {
|
|
157
|
+
constructor(config) {
|
|
158
|
+
// Call the ApolloServer constructor
|
|
159
|
+
super(config);
|
|
160
|
+
|
|
161
|
+
// Add the plugin to the plugins array
|
|
162
|
+
this.addPlugin(appDynamicsApolloServerPlugin(self));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return ApolloServerProxy;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function proxyStartStandaloneServer(self, originalObject) {
|
|
85
170
|
return async function startStandaloneServerProxy(server, options) {
|
|
86
|
-
const overriddenOptions = options
|
|
87
|
-
|
|
88
|
-
const context = options ? options.context : undefined;
|
|
89
|
-
const overriddenContext = async function (contextParam) {
|
|
90
|
-
const contextValue = context ? await context(contextParam) : {};
|
|
91
|
-
contextValue.gqlReq = contextParam.req;
|
|
92
|
-
contextValue.gqlRes = contextParam.res;
|
|
93
|
-
return contextValue;
|
|
94
|
-
};
|
|
95
|
-
overriddenOptions.context = overriddenContext;
|
|
96
|
-
|
|
97
|
-
const plugin = {
|
|
98
|
-
async requestDidStart() {
|
|
99
|
-
return {
|
|
100
|
-
didResolveOperation(requestContext) {
|
|
101
|
-
requestContext.contextValue.gqlReq.graphqlop = requestContext.operationName;
|
|
102
|
-
requestContext.contextValue.gqlReq.transactionStarted = true;
|
|
103
|
-
|
|
104
|
-
HttpCommon.startTransactionHandler(
|
|
105
|
-
requestContext.contextValue.gqlReq,
|
|
106
|
-
requestContext.contextValue.gqlRes,
|
|
107
|
-
self.agent
|
|
108
|
-
);
|
|
109
|
-
},
|
|
110
|
-
didEncounterErrors(requestContext) {
|
|
111
|
-
requestContext.contextValue.gqlRes.error = requestContext.errors[0];
|
|
112
|
-
if(requestContext.contextValue.gqlReq.transactionStarted) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
HttpCommon.startTransactionHandler(
|
|
116
|
-
requestContext.contextValue.gqlReq,
|
|
117
|
-
requestContext.contextValue.gqlRes,
|
|
118
|
-
self.agent
|
|
119
|
-
);
|
|
120
|
-
},
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
server.addPlugin(plugin);
|
|
171
|
+
const overriddenOptions = appDymanicsApolloServerOverriddenOptions(options);
|
|
125
172
|
return await originalObject.startStandaloneServer(server, overriddenOptions);
|
|
126
173
|
};
|
|
127
174
|
}
|
|
175
|
+
|
|
176
|
+
function proxyExpressMiddleware(self, originalObject) {
|
|
177
|
+
return function expressMiddlewareProxy(server, options) {
|
|
178
|
+
const overriddenOptions = appDymanicsApolloServerOverriddenOptions(options);
|
|
179
|
+
return originalObject.expressMiddleware(server, overriddenOptions);
|
|
180
|
+
};
|
|
181
|
+
}
|
|
@@ -10,6 +10,7 @@ module.exports.getHttpStatusCodeConfig = getHttpStatusCodeConfig;
|
|
|
10
10
|
module.exports.generateError = generateError;
|
|
11
11
|
module.exports.getHttpExitCallError = getHttpExitCallError;
|
|
12
12
|
module.exports.finalizeTransaction = finalizeTransaction;
|
|
13
|
+
module.exports.finalizeRequest = finalizeRequest;
|
|
13
14
|
module.exports.startTransactionHandler = startTransactionHandler;
|
|
14
15
|
|
|
15
16
|
|
|
@@ -66,10 +67,30 @@ function getHttpExitCallError(statusCode, stack, locals) {
|
|
|
66
67
|
return error;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
function finalizeTransaction (err, profiler, time, transaction, req, res, span) {
|
|
70
|
+
function finalizeRequest(err, profiler, time, transaction, req, res, span, sep) {
|
|
71
71
|
if (!time.done()) return;
|
|
72
|
+
finalizeTransaction(err, profiler, time, transaction, req, res, span);
|
|
73
|
+
finalizeServiceEndpoint(err, profiler, time, sep, res);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function finalizeServiceEndpoint (err, profiler, time, sep, res) {
|
|
77
|
+
if(!sep) return;
|
|
78
|
+
sep.error = sep.error || res.error || err;
|
|
79
|
+
sep.statusCode = sep.statusCode ||
|
|
80
|
+
(sep.error && sep.error.statusCode) ||
|
|
81
|
+
(res && res.statusCode) ||
|
|
82
|
+
500;
|
|
83
|
+
sep.stackTrace = sep.stackTrace || profiler.formatStackTrace(sep.error);
|
|
84
|
+
|
|
85
|
+
var error = generateError(sep.error, sep.statusCode);
|
|
86
|
+
if (error) {
|
|
87
|
+
sep.error = error;
|
|
88
|
+
}
|
|
89
|
+
profiler.endServiceEndpoint(time, sep);
|
|
90
|
+
}
|
|
91
|
+
|
|
72
92
|
|
|
93
|
+
function finalizeTransaction (err, profiler, time, transaction, req, res, span) {
|
|
73
94
|
transaction.error = transaction.error || res.error || err;
|
|
74
95
|
transaction.statusCode = transaction.statusCode ||
|
|
75
96
|
(transaction.error && transaction.error.statusCode) ||
|
|
@@ -108,7 +129,7 @@ function startTransactionHandler(req, res, agent, isHTTPs, tracer, ot_api) {
|
|
|
108
129
|
var span = undefined;
|
|
109
130
|
var baggageCorrHeader = undefined;
|
|
110
131
|
var otContext = undefined;
|
|
111
|
-
|
|
132
|
+
|
|
112
133
|
if (tracer) {
|
|
113
134
|
otContext = ot_api.propagation.extract(agent.TracerProvider.ot_api.ROOT_CONTEXT, req.headers);
|
|
114
135
|
var baggage = ot_api.propagation.getBaggage(otContext);
|
|
@@ -151,10 +172,13 @@ function startTransactionHandler(req, res, agent, isHTTPs, tracer, ot_api) {
|
|
|
151
172
|
});
|
|
152
173
|
}
|
|
153
174
|
|
|
175
|
+
var serviceEndpoint = profiler.startServiceEndpoint(time, req, 'NODEJS_WEB');
|
|
176
|
+
|
|
154
177
|
proxy.after(res, "end", function () {
|
|
155
|
-
|
|
178
|
+
finalizeRequest(null, profiler, time, transaction, req, res, span, serviceEndpoint);
|
|
156
179
|
transaction = null;
|
|
180
|
+
serviceEndpoint = null;
|
|
157
181
|
});
|
|
158
182
|
|
|
159
|
-
return { transaction, span, otContext };
|
|
183
|
+
return { transaction, span, otContext, serviceEndpoint };
|
|
160
184
|
}
|
|
@@ -115,7 +115,7 @@ HttpEntryProbe.prototype.__createRequestHandler = function (callback, isHTTPs) {
|
|
|
115
115
|
|
|
116
116
|
self.agent.metricsManager.addMetric(self.agent.metricsManager.HTTP_INCOMING_COUNT, 1);
|
|
117
117
|
|
|
118
|
-
let { transaction, span, otContext } = HttpCommon.startTransactionHandler(req, res, self.agent, isHTTPs, self.tracer, self.ot_api);
|
|
118
|
+
let { transaction, span, otContext, serviceEndpoint } = HttpCommon.startTransactionHandler(req, res, self.agent, isHTTPs, self.tracer, self.ot_api);
|
|
119
119
|
|
|
120
120
|
var threadId = transaction.threadId;
|
|
121
121
|
self.agent.context.run(() => {
|
|
@@ -127,7 +127,8 @@ HttpEntryProbe.prototype.__createRequestHandler = function (callback, isHTTPs) {
|
|
|
127
127
|
let threadProxyWrappedCb = self.agent.proxy.wrapWithThreadProxyIfEnabled(callback);
|
|
128
128
|
return invokeOriginal(threadProxyWrappedCb, this, arguments, self.ot_api, span, otContext, req, res);
|
|
129
129
|
} catch (e) {
|
|
130
|
-
HttpCommon.
|
|
130
|
+
HttpCommon.finalizeRequest(e, profiler, time, transaction, req, res, span, serviceEndpoint);
|
|
131
|
+
serviceEndpoint = null;
|
|
131
132
|
transaction = null;
|
|
132
133
|
throw e;
|
|
133
134
|
} finally {
|
|
@@ -140,6 +141,6 @@ HttpEntryProbe.prototype.__createRequestHandler = function (callback, isHTTPs) {
|
|
|
140
141
|
// This is needed as Express attaches a bunch of extra properties and
|
|
141
142
|
// functionality, which may need to be accessed by other modules down stream.
|
|
142
143
|
handler.__proto__ = callback;
|
|
143
|
-
|
|
144
|
+
|
|
144
145
|
return handler;
|
|
145
146
|
};
|
package/lib/probes/http-probe.js
CHANGED
|
@@ -9,7 +9,7 @@ var HttpEntryProbe = require('./http-entry-probe').HttpEntryProbe;
|
|
|
9
9
|
var HttpExitProbe = require('./http-exit-probe').HttpExitProbe;
|
|
10
10
|
var ApolloEntryProbe = require('./apollo-entry-probe').ApolloEntryProbe;
|
|
11
11
|
|
|
12
|
-
const apolloPackages = ['apollo-server', '@apollo/server/standalone'];
|
|
12
|
+
const apolloPackages = ['apollo-server', '@apollo/server/standalone', '@apollo/server/express4', '@apollo/server'];
|
|
13
13
|
|
|
14
14
|
function HttpProbe(agent) {
|
|
15
15
|
this.agent = agent;
|
|
@@ -58,9 +58,21 @@ HttpProbe.prototype.attach = function (obj, moduleName) {
|
|
|
58
58
|
}
|
|
59
59
|
} else if (moduleName === '@apollo/server/standalone') {
|
|
60
60
|
if(self.agent.opts.enableGraphQL) {
|
|
61
|
+
obj.__appdynamicsProbeAttached__ = false;
|
|
61
62
|
return this.apolloEntryProbe.attach(obj, moduleName);
|
|
62
63
|
}
|
|
63
|
-
} else if
|
|
64
|
+
} else if(moduleName === '@apollo/server/express4') {
|
|
65
|
+
if(self.agent.opts.enableGraphQL) {
|
|
66
|
+
obj.__appdynamicsProbeAttached__ = false;
|
|
67
|
+
return this.apolloEntryProbe.attach(obj, moduleName);
|
|
68
|
+
}
|
|
69
|
+
} else if(moduleName === '@apollo/server') {
|
|
70
|
+
if(self.agent.opts.enableGraphQL) {
|
|
71
|
+
obj.__appdynamicsProbeAttached__ = false;
|
|
72
|
+
return this.apolloEntryProbe.attach(obj, moduleName);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (moduleName.includes('graphql-http')) {
|
|
64
76
|
if(self.agent.opts.enableGraphQL) {
|
|
65
77
|
this.entryProbe.enableGraphQLHttp(obj);
|
|
66
78
|
}
|
|
@@ -283,7 +283,7 @@ MongodbProbe.prototype.attach = function (obj) {
|
|
|
283
283
|
proxy.before(obj.MongoClient.prototype, 'connect', function(obj){
|
|
284
284
|
obj.monitorCommands = true;
|
|
285
285
|
var newServerPool;
|
|
286
|
-
var newOpQueue =
|
|
286
|
+
var newOpQueue = new Map();
|
|
287
287
|
var newApmCollectionEvents = ['create', 'drop'];
|
|
288
288
|
var newCollectionCommandMap = {
|
|
289
289
|
'create': 'createCollection',
|
|
@@ -306,13 +306,13 @@ MongodbProbe.prototype.attach = function (obj) {
|
|
|
306
306
|
newServerPool = [event.address];
|
|
307
307
|
}
|
|
308
308
|
if (newServerPool) {
|
|
309
|
-
if (!newOpQueue
|
|
310
|
-
newOpQueue
|
|
309
|
+
if (!newOpQueue.has(requestId)) {
|
|
310
|
+
newOpQueue.set(requestId, {
|
|
311
311
|
time: profiler.time(),
|
|
312
312
|
serverPool: newServerPool
|
|
313
|
-
};
|
|
313
|
+
});
|
|
314
314
|
}
|
|
315
|
-
newRequest = newOpQueue
|
|
315
|
+
newRequest = newOpQueue.get(requestId);
|
|
316
316
|
newCommandQuery = event.command.filter;
|
|
317
317
|
if (event.command.filter && Object.prototype.toString.call(event.command.filter) == "[object Object]") {
|
|
318
318
|
newCommandQuery = utility.filterSensitiveDataFromObject(utility.deepCopy(event.command.filter));
|
|
@@ -334,18 +334,18 @@ MongodbProbe.prototype.attach = function (obj) {
|
|
|
334
334
|
});
|
|
335
335
|
|
|
336
336
|
obj.on('commandSucceeded', function (event) {
|
|
337
|
-
var requestId = event.requestId, newRequest = newOpQueue
|
|
337
|
+
var requestId = event.requestId, newRequest = newOpQueue.get(requestId);
|
|
338
338
|
if (newRequest) {
|
|
339
339
|
self.addExitCall(newRequest.time, newRequest.exitCall);
|
|
340
|
-
newOpQueue
|
|
340
|
+
newOpQueue.delete(requestId);
|
|
341
341
|
}
|
|
342
342
|
});
|
|
343
343
|
|
|
344
344
|
obj.on('commandFailed', function (event) {
|
|
345
|
-
var requestId = event.requestId, newRequest = newOpQueue
|
|
345
|
+
var requestId = event.requestId, newRequest = newOpQueue.get(requestId);
|
|
346
346
|
if (newRequest) {
|
|
347
347
|
self.addExitCall(event.time, event.exitCall, event.failure);
|
|
348
|
-
newOpQueue
|
|
348
|
+
newOpQueue.delete(requestId);
|
|
349
349
|
}
|
|
350
350
|
});
|
|
351
351
|
});
|
package/lib/profiler/profiler.js
CHANGED
|
@@ -19,6 +19,7 @@ function Profiler(agent) {
|
|
|
19
19
|
this.agent = agent;
|
|
20
20
|
|
|
21
21
|
this.transactions = {};
|
|
22
|
+
this.serviceEndpoints = {};
|
|
22
23
|
this.stackTraceFilter = /appdynamics/;
|
|
23
24
|
}
|
|
24
25
|
exports.Profiler = Profiler;
|
|
@@ -83,6 +84,43 @@ Profiler.prototype.formatStackTrace = function (err) {
|
|
|
83
84
|
return undefined;
|
|
84
85
|
};
|
|
85
86
|
|
|
87
|
+
Profiler.prototype.startServiceEndpoint = function(time, req, entryType) {
|
|
88
|
+
var self = this;
|
|
89
|
+
var sep = {};
|
|
90
|
+
sep.time = time;
|
|
91
|
+
sep.id = time.id;
|
|
92
|
+
sep.threadId = time.threadId;
|
|
93
|
+
sep.entryType = entryType;
|
|
94
|
+
|
|
95
|
+
self.serviceEndpoints[time.threadId] = sep;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
self.agent.emit('serviceEndpointStart', sep, req);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
self.agent.logger.warn(err);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return sep;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
Profiler.prototype.endServiceEndpoint = function (time, sep) {
|
|
107
|
+
var self = this;
|
|
108
|
+
|
|
109
|
+
if (sep.isFinished) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
sep.isFinished = true;
|
|
114
|
+
sep.ms = time.ms;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
self.agent.emit('serviceEndpointStop', sep);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
self.agent.logger.warn(err);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
delete self.serviceEndpoints[time.threadId];
|
|
123
|
+
};
|
|
86
124
|
|
|
87
125
|
Profiler.prototype.startTransaction = function(time, req, entryType, baggageCorrHeader) {
|
|
88
126
|
var self = this;
|
|
@@ -184,6 +222,11 @@ Profiler.prototype.isValidThreadId = function(threadId) {
|
|
|
184
222
|
return (threadId && self.transactions[threadId]);
|
|
185
223
|
};
|
|
186
224
|
|
|
225
|
+
Profiler.prototype.isValidSepThreadId = function(threadId) {
|
|
226
|
+
var self = this;
|
|
227
|
+
return (threadId && self.serviceEndpoints[threadId]);
|
|
228
|
+
};
|
|
229
|
+
|
|
187
230
|
Profiler.prototype._endTransaction = function (time, transaction) {
|
|
188
231
|
var self = this;
|
|
189
232
|
|
|
@@ -217,6 +260,18 @@ Profiler.prototype.transactionDropped = function (guid) {
|
|
|
217
260
|
}
|
|
218
261
|
};
|
|
219
262
|
|
|
263
|
+
Profiler.prototype.sepDropped = function (guid) {
|
|
264
|
+
var self = this;
|
|
265
|
+
|
|
266
|
+
for (var threadId in self.serviceEndpoints) {
|
|
267
|
+
if (self.serviceEndpoints[threadId].sepGuid === guid) {
|
|
268
|
+
self.agent.logger.info('SEP ' + self.serviceEndpoints[threadId].id + ' dropped');
|
|
269
|
+
delete self.serviceEndpoints[threadId];
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
220
275
|
Profiler.prototype.__getNextSequenceInfo = function (transaction) {
|
|
221
276
|
var self = this;
|
|
222
277
|
transaction.exitCallCounter++;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appdynamics",
|
|
3
|
-
"version": "24.
|
|
3
|
+
"version": "24.12.0",
|
|
4
4
|
"description": "Performance Profiler and Monitor",
|
|
5
5
|
"author": "AppDynamics, Inc.",
|
|
6
6
|
"homepage": "https://www.appdynamics.com",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"https-proxy-agent": "^5.0.1",
|
|
52
52
|
"uuid": "^8.3.2",
|
|
53
53
|
"y18n": "^5.0.8",
|
|
54
|
-
"appdynamics-libagent-napi": "https://cdn.appdynamics.com/packages/nodejs/24.
|
|
55
|
-
"appdynamics-native": "https://cdn.appdynamics.com/packages/nodejs/24.
|
|
56
|
-
"appdynamics-protobuf": "https://cdn.appdynamics.com/packages/nodejs/24.
|
|
54
|
+
"appdynamics-libagent-napi": "https://cdn.appdynamics.com/packages/nodejs/24.12.0.0/appdynamics-libagent-napi-node.tgz",
|
|
55
|
+
"appdynamics-native": "https://cdn.appdynamics.com/packages/nodejs/24.12.0.0/appdynamics-native-node.tgz",
|
|
56
|
+
"appdynamics-protobuf": "https://cdn.appdynamics.com/packages/nodejs/24.12.0.0/appdynamics-protobuf-node.tgz"
|
|
57
57
|
},
|
|
58
58
|
"overrides": {
|
|
59
59
|
"semver": "7.5.4"
|
package/packageBck.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appdynamics",
|
|
3
|
-
"version": "24.
|
|
3
|
+
"version": "24.12.0",
|
|
4
4
|
"description": "Performance Profiler and Monitor",
|
|
5
5
|
"author": "AppDynamics, Inc.",
|
|
6
6
|
"homepage": "https://www.appdynamics.com",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"https-proxy-agent": "^5.0.1",
|
|
52
52
|
"uuid": "^8.3.2",
|
|
53
53
|
"y18n": "^5.0.8",
|
|
54
|
-
"appdynamics-libagent-napi": "https://cdn.appdynamics.com/packages/nodejs/24.
|
|
55
|
-
"appdynamics-native": "https://cdn.appdynamics.com/packages/nodejs/24.
|
|
56
|
-
"appdynamics-protobuf": "https://cdn.appdynamics.com/packages/nodejs/24.
|
|
54
|
+
"appdynamics-libagent-napi": "https://cdn.appdynamics.com/packages/nodejs/24.12.0.0/appdynamics-libagent-napi-node.tgz",
|
|
55
|
+
"appdynamics-native": "https://cdn.appdynamics.com/packages/nodejs/24.12.0.0/appdynamics-native-node.tgz",
|
|
56
|
+
"appdynamics-protobuf": "https://cdn.appdynamics.com/packages/nodejs/24.12.0.0/appdynamics-protobuf-node.tgz"
|
|
57
57
|
},
|
|
58
58
|
"overrides": {
|
|
59
59
|
"semver": "7.5.4"
|