diff --git a/packages/core/src/tracing/instrumentation/cloud/aws-sdk/v3/sqs-consumer.js b/packages/core/src/tracing/instrumentation/cloud/aws-sdk/v3/sqs-consumer.js index cd29f1aba6..a5ce0781a2 100644 --- a/packages/core/src/tracing/instrumentation/cloud/aws-sdk/v3/sqs-consumer.js +++ b/packages/core/src/tracing/instrumentation/cloud/aws-sdk/v3/sqs-consumer.js @@ -24,17 +24,19 @@ function instrument(SQSConsumer) { span.disableAutoEnd(); const res = orig.apply(this, arguments); - res - .then(() => { - span.d = Date.now() - span.ts; - span.transmitManual(); - }) - .catch(err => { - span.ec = 1; - tracingUtil.setErrorDetails(span, err, 'sqs'); - span.d = Date.now() - span.ts; - span.transmitManual(); - }); + if (res && typeof res.then === 'function') { + res + .then(() => { + span.d = Date.now() - span.ts; + span.transmitManual(); + }) + .catch(err => { + span.ec = 1; + tracingUtil.setErrorDetails(span, err, 'sqs'); + span.d = Date.now() - span.ts; + span.transmitManual(); + }); + } return res; }); @@ -56,17 +58,19 @@ function instrument(SQSConsumer) { span.disableAutoEnd(); const res = orig.apply(this, arguments); - res - .then(() => { - span.d = Date.now() - span.ts; - span.transmitManual(); - }) - .catch(err => { - span.ec = 1; - tracingUtil.setErrorDetails(span, err, 'sqs'); - span.d = Date.now() - span.ts; - span.transmitManual(); - }); + if (res && typeof res.then === 'function') { + res + .then(() => { + span.d = Date.now() - span.ts; + span.transmitManual(); + }) + .catch(err => { + span.ec = 1; + tracingUtil.setErrorDetails(span, err, 'sqs'); + span.d = Date.now() - span.ts; + span.transmitManual(); + }); + } return res; }); diff --git a/packages/core/src/tracing/instrumentation/cloud/gcp/storage.js b/packages/core/src/tracing/instrumentation/cloud/gcp/storage.js index c1d4fbb43d..f91612dbe1 100644 --- a/packages/core/src/tracing/instrumentation/cloud/gcp/storage.js +++ b/packages/core/src/tracing/instrumentation/cloud/gcp/storage.js @@ -416,7 +416,7 @@ function instrumentedOperation(operation, extractorPre, extractorPost, ctx, orig } const promise = original.apply(ctx, originalArgs); - if (promise) { + if (promise && typeof promise.then === 'function') { promise.then( result => finishSpan(null, Array.isArray(result) ? result[0] : result, span, extractorPost), e => finishSpan(e, null, span, extractorPost) diff --git a/packages/core/src/tracing/instrumentation/control_flow/graphqlSubscriptions.js b/packages/core/src/tracing/instrumentation/control_flow/graphqlSubscriptions.js index 8197259f91..e7edc1daba 100644 --- a/packages/core/src/tracing/instrumentation/control_flow/graphqlSubscriptions.js +++ b/packages/core/src/tracing/instrumentation/control_flow/graphqlSubscriptions.js @@ -62,18 +62,23 @@ function shimPushValue(originalFunction) { function shimPullValue(originalFunction) { return function () { const pullPromise = originalFunction.apply(this, arguments); - return pullPromise.then(result => { - if (result && result.value && result.value[CLS_CONTEXT_SYMBOL]) { - const clsContext = result.value[CLS_CONTEXT_SYMBOL]; - if (isActive && clsContext) { - cls.ns.enter(clsContext); - setImmediate(() => { - cls.ns.exit(clsContext); - }); + + if (pullPromise && typeof pullPromise.then === 'function') { + return pullPromise.then(result => { + if (result && result.value && result.value[CLS_CONTEXT_SYMBOL]) { + const clsContext = result.value[CLS_CONTEXT_SYMBOL]; + if (isActive && clsContext) { + cls.ns.enter(clsContext); + setImmediate(() => { + cls.ns.exit(clsContext); + }); + } } - } - return result; - }); + return result; + }); + } + + return pullPromise; }; } diff --git a/packages/core/src/tracing/instrumentation/databases/couchbase.js b/packages/core/src/tracing/instrumentation/databases/couchbase.js index 2d7a0df358..dee2b58472 100644 --- a/packages/core/src/tracing/instrumentation/databases/couchbase.js +++ b/packages/core/src/tracing/instrumentation/databases/couchbase.js @@ -77,7 +77,7 @@ function instrumentConnect(originalConnect) { const prom = originalConnect.apply(originalThis, originalArgs); - if (prom && prom.then) { + if (prom && typeof prom.then === 'function') { prom.then(cluster => { instrumentCluster(cluster, connectionStr); return cluster; @@ -488,7 +488,7 @@ function instrumentOperation({ connectionStr, bucketName, getBucketTypeFn, sql, if (callbackIndex < 0) { const prom = original.apply(originalThis, originalArgs); - if (prom.then && prom.catch) { + if (typeof prom?.then === 'function' && typeof prom?.catch === 'function') { prom .then(result => { if (resultHandler) { diff --git a/packages/core/src/tracing/instrumentation/databases/elasticsearch.js b/packages/core/src/tracing/instrumentation/databases/elasticsearch.js index 4877c53604..46a6f2b774 100644 --- a/packages/core/src/tracing/instrumentation/databases/elasticsearch.js +++ b/packages/core/src/tracing/instrumentation/databases/elasticsearch.js @@ -155,10 +155,14 @@ function instrumentApi(client, actionPath, clusterInfo) { } else { // eslint-disable-next-line no-useless-catch try { - return originalFunction.apply(ctx, originalArgs).then(onSuccess.bind(null, span), error => { - onError(span, error); - throw error; - }); + const promise = originalFunction.apply(ctx, originalArgs); + if (typeof promise?.then === 'function') { + return promise.then(onSuccess.bind(null, span), error => { + onError(span, error); + throw error; + }); + } + return promise; } catch (e) { // Immediately cleanup on synchronous errors. throw e; @@ -448,10 +452,14 @@ function instrumentedRequest(ctx, origEsReq, originalArgs) { } else { // eslint-disable-next-line no-useless-catch try { - return origEsReq.apply(ctx, originalArgs).then(onSuccess.bind(null, span), error => { - onError(span, error); - throw error; - }); + const promise = origEsReq.apply(ctx, originalArgs); + if (typeof promise?.then === 'function') { + return promise.then(onSuccess.bind(null, span), error => { + onError(span, error); + throw error; + }); + } + return promise; } catch (e) { // Immediately cleanup on synchronous errors. throw e; diff --git a/packages/core/src/tracing/instrumentation/databases/ioredis.js b/packages/core/src/tracing/instrumentation/databases/ioredis.js index e88a1c69e3..f20dc059b7 100644 --- a/packages/core/src/tracing/instrumentation/databases/ioredis.js +++ b/packages/core/src/tracing/instrumentation/databases/ioredis.js @@ -97,11 +97,13 @@ function instrumentSendCommand(original) { span.stack = tracingUtil.getStackTrace(wrappedInternalSendCommand); callback = cls.ns.bind(onResult); - command.promise.then( - // make sure that the first parameter is never truthy - callback.bind(null, null), - callback - ); + if (typeof command.promise?.then === 'function') { + command.promise.then( + // make sure that the first parameter is never truthy + callback.bind(null, null), + callback + ); + } return original.apply(client, argsForOriginal); @@ -190,7 +192,7 @@ function instrumentMultiOrPipelineExec(clsContextForMultiOrPipeline, commandName span.ts = Date.now(); const result = original.apply(this, arguments); - if (result.then) { + if (typeof result?.then === 'function') { result.then( results => { endCallback.call(null, clsContextForMultiOrPipeline, span, null, results); diff --git a/packages/core/src/tracing/instrumentation/databases/mongodb.js b/packages/core/src/tracing/instrumentation/databases/mongodb.js index 7582e1917c..b2928bf976 100644 --- a/packages/core/src/tracing/instrumentation/databases/mongodb.js +++ b/packages/core/src/tracing/instrumentation/databases/mongodb.js @@ -457,7 +457,7 @@ function handleCallbackOrPromise(ctx, originalArgs, originalFunction, span) { const resultPromise = originalFunction.apply(ctx, originalArgs); - if (resultPromise && resultPromise.then) { + if (resultPromise && typeof resultPromise.then === 'function') { resultPromise .then(result => { span.d = Date.now() - span.ts; diff --git a/packages/core/src/tracing/instrumentation/databases/mssql.js b/packages/core/src/tracing/instrumentation/databases/mssql.js index d1cf837774..ddd5f199fe 100644 --- a/packages/core/src/tracing/instrumentation/databases/mssql.js +++ b/packages/core/src/tracing/instrumentation/databases/mssql.js @@ -88,7 +88,7 @@ function instrumentedMethod(ctx, originalFunction, originalArgs, stackTraceRef, } const promise = originalFunction.apply(ctx, originalArgs); - if (typeof promise.then === 'function') { + if (typeof promise?.then === 'function') { promise .then(value => { finishSpan(null, span); diff --git a/packages/core/src/tracing/instrumentation/databases/mysql.js b/packages/core/src/tracing/instrumentation/databases/mysql.js index a33688fa86..603fa058f2 100644 --- a/packages/core/src/tracing/instrumentation/databases/mysql.js +++ b/packages/core/src/tracing/instrumentation/databases/mysql.js @@ -182,20 +182,23 @@ function instrumentedAccessFunction( if (isPromiseImpl) { const resultPromise = originalFunction.apply(ctx, originalArgs); - resultPromise - .then(result => { - span.d = Date.now() - span.ts; - span.transmit(); - return result; - }) - .catch(error => { - span.ec = 1; - tracingUtil.setErrorDetails(span, error, exports.spanName); - - span.d = Date.now() - span.ts; - span.transmit(); - return error; - }); + if (typeof resultPromise?.then === 'function') { + resultPromise + .then(result => { + span.d = Date.now() - span.ts; + span.transmit(); + return result; + }) + .catch(error => { + span.ec = 1; + tracingUtil.setErrorDetails(span, error, exports.spanName); + + span.d = Date.now() - span.ts; + span.transmit(); + throw error; + }); + } + return resultPromise; } @@ -238,12 +241,15 @@ function shimGetConnection(original) { function shimPromiseConnection(original) { return function getConnection() { - return original.apply(this, arguments).then(connection => { - shimmer.wrap(connection, 'query', shimPromiseQuery); - shimmer.wrap(connection, 'execute', shimPromiseExecute); - - return connection; - }); + const promise = original.apply(this, arguments); + if (typeof promise?.then === 'function') { + return promise.then(connection => { + shimmer.wrap(connection, 'query', shimPromiseQuery); + shimmer.wrap(connection, 'execute', shimPromiseExecute); + + return connection; + }); + } }; } diff --git a/packages/core/src/tracing/instrumentation/frameworks/koa.js b/packages/core/src/tracing/instrumentation/frameworks/koa.js index 48b72c57b4..a7eed9244b 100644 --- a/packages/core/src/tracing/instrumentation/frameworks/koa.js +++ b/packages/core/src/tracing/instrumentation/frameworks/koa.js @@ -61,20 +61,21 @@ function instrumentedRoutes(thisContext, originalRoutes, originalArgs) { const instrumentedDispatch = function (ctx, next) { if (active && cls.isTracing()) { const dispatchResult = dispatch.apply(this, arguments); - return dispatchResult.then(resolvedValue => { - if (ctx.matched && ctx.matched.length && ctx.matched.length > 0) { - const matchedRouteLayers = ctx.matched.slice(); - matchedRouteLayers.sort(byLeastSpecificLayer); - const mostSpecificPath = normalizeLayerPath(matchedRouteLayers[matchedRouteLayers.length - 1].path); - annotateHttpEntrySpanWithPathTemplate(mostSpecificPath); - } - return resolvedValue; - }); + if (typeof dispatchResult?.then === 'function') { + return dispatchResult.then(resolvedValue => { + if (ctx.matched && ctx.matched.length && ctx.matched.length > 0) { + const matchedRouteLayers = ctx.matched.slice(); + matchedRouteLayers.sort(byLeastSpecificLayer); + const mostSpecificPath = normalizeLayerPath(matchedRouteLayers[matchedRouteLayers.length - 1].path); + annotateHttpEntrySpanWithPathTemplate(mostSpecificPath); + } + return resolvedValue; + }); + } } else { return dispatch.apply(this, arguments); } }; - // The router attaches itself as a property to the dispatch function and other methods in koa-router rely on this, so // we need to attach this property to our dispatch function, too. instrumentedDispatch.router = dispatch.router; diff --git a/packages/core/src/tracing/instrumentation/messaging/amqp.js b/packages/core/src/tracing/instrumentation/messaging/amqp.js index d0fcad6b46..6608c1931c 100644 --- a/packages/core/src/tracing/instrumentation/messaging/amqp.js +++ b/packages/core/src/tracing/instrumentation/messaging/amqp.js @@ -249,56 +249,60 @@ function instrumentedChannelModelGet(ctx, originalGet, originalArgs) { kind: constants.ENTRY }); - return originalGet.apply(ctx, originalArgs).then(result => { - if (!result) { - // get did not fetch a new message from RabbitMQ (because the queue has no messages), no need to create a span. - span.cancel(); - return result; - } - const fields = result.fields || {}; - const headers = result.properties && result.properties.headers ? result.properties.headers : {}; - - if (tracingUtil.readAttribCaseInsensitive(headers, constants.traceLevelHeaderName) === '0') { - cls.setTracingLevel('0'); - span.cancel(); - return result; - } + const promise = originalGet.apply(ctx, originalArgs); + if (typeof promise?.then === 'function') { + return promise.then(result => { + if (!result) { + // get did not fetch a new message from RabbitMQ (because the queue has no messages), no need to create a + // span. + span.cancel(); + return result; + } + const fields = result.fields || {}; + const headers = result.properties && result.properties.headers ? result.properties.headers : {}; - const traceId = tracingUtil.readAttribCaseInsensitive(headers, constants.traceIdHeaderName); - const parentSpanId = tracingUtil.readAttribCaseInsensitive(headers, constants.spanIdHeaderName); - if (traceId && parentSpanId) { - span.t = traceId; - span.p = parentSpanId; - } + if (tracingUtil.readAttribCaseInsensitive(headers, constants.traceLevelHeaderName) === '0') { + cls.setTracingLevel('0'); + span.cancel(); + return result; + } - span.ts = Date.now(); - span.stack = tracingUtil.getStackTrace(instrumentedChannelModelGet); - span.data.rabbitmq = { - sort: 'consume' - }; + const traceId = tracingUtil.readAttribCaseInsensitive(headers, constants.traceIdHeaderName); + const parentSpanId = tracingUtil.readAttribCaseInsensitive(headers, constants.spanIdHeaderName); + if (traceId && parentSpanId) { + span.t = traceId; + span.p = parentSpanId; + } - if (ctx.connection.stream) { - span.data.rabbitmq.address = - typeof ctx.connection.stream.getProtocol === 'function' - ? 'amqps://' - : // - `amqp://${ctx.connection.stream.remoteAddress}:${ctx.connection.stream.remotePort}`; - } - if (fields.exchange) { - span.data.rabbitmq.exchange = fields.exchange; - } - if (fields.routingKey) { - span.data.rabbitmq.key = fields.routingKey; - } + span.ts = Date.now(); + span.stack = tracingUtil.getStackTrace(instrumentedChannelModelGet); + span.data.rabbitmq = { + sort: 'consume' + }; + + if (ctx.connection.stream) { + span.data.rabbitmq.address = + typeof ctx.connection.stream.getProtocol === 'function' + ? 'amqps://' + : // + `amqp://${ctx.connection.stream.remoteAddress}:${ctx.connection.stream.remotePort}`; + } + if (fields.exchange) { + span.data.rabbitmq.exchange = fields.exchange; + } + if (fields.routingKey) { + span.data.rabbitmq.key = fields.routingKey; + } - setImmediate(() => { - // Client code is expected to end the span manually, end it automatically in case client code doesn't. Child - // exit spans won't be captured, but at least the RabbitMQ entry span is there. - span.d = Date.now() - span.ts; - span.transmit(); + setImmediate(() => { + // Client code is expected to end the span manually, end it automatically in case client code doesn't. Child + // exit spans won't be captured, but at least the RabbitMQ entry span is there. + span.d = Date.now() - span.ts; + span.transmit(); + }); + return result; }); - return result; - }); + } }); } diff --git a/packages/core/src/tracing/instrumentation/messaging/bull.js b/packages/core/src/tracing/instrumentation/messaging/bull.js index f09fc0474d..39f7cdadc9 100644 --- a/packages/core/src/tracing/instrumentation/messaging/bull.js +++ b/packages/core/src/tracing/instrumentation/messaging/bull.js @@ -100,15 +100,17 @@ function instrumentedJobCreate(ctx, originalJobCreate, originalArgs, options) { const promise = originalJobCreate.apply(ctx, originalArgs); - return promise - .then(job => { - finishSpan(null, job, span); - return job; - }) - .catch(err => { - finishSpan(err, null, span); - return err; - }); + if (typeof promise?.then === 'function') { + return promise + .then(job => { + finishSpan(null, job, span); + return job; + }) + .catch(err => { + finishSpan(err, null, span); + return err; + }); + } }); } @@ -258,20 +260,22 @@ function instrumentedProcessJob(ctx, originalProcessJob, originalArgs) { const promise = originalProcessJob.apply(ctx, originalArgs); - return promise - .then(data => { - finishSpan(job.failedReason, data, span); - // Make sure the instana foreigner data is removed. - delete options.X_INSTANA_L; - return data; - }) - .catch(err => { - addErrorToSpan(err, span); - finishSpan(null, null, span); - // Make sure the instana foreigner data is removed. - delete options.X_INSTANA_L; - throw err; - }); + if (promise && typeof promise.then === 'function') { + return promise + .then(data => { + finishSpan(job.failedReason, data, span); + // Make sure the instana foreigner data is removed. + delete options.X_INSTANA_L; + return data; + }) + .catch(err => { + addErrorToSpan(err, span); + finishSpan(null, null, span); + // Make sure the instana foreigner data is removed. + delete options.X_INSTANA_L; + throw err; + }); + } }); } diff --git a/packages/core/src/tracing/instrumentation/messaging/kafkaJs.js b/packages/core/src/tracing/instrumentation/messaging/kafkaJs.js index f887225f13..0a44ce1626 100644 --- a/packages/core/src/tracing/instrumentation/messaging/kafkaJs.js +++ b/packages/core/src/tracing/instrumentation/messaging/kafkaJs.js @@ -96,20 +96,22 @@ function instrumentedSend(ctx, originalSend, originalArgs, topic, messages) { } span.stack = tracingUtil.getStackTrace(instrumentedSend); - return originalSend - .apply(ctx, originalArgs) - .then(result => { - span.d = Date.now() - span.ts; - span.transmit(); - return result; - }) - .catch(error => { - span.ec = 1; - tracingUtil.setErrorDetails(span, error, 'kafka'); - span.d = Date.now() - span.ts; - span.transmit(); - throw error; - }); + const promise = originalSend.apply(ctx, originalArgs); + if (typeof promise?.then === 'function') { + return promise + .then(result => { + span.d = Date.now() - span.ts; + span.transmit(); + return result; + }) + .catch(error => { + span.ec = 1; + tracingUtil.setErrorDetails(span, error, 'kafka'); + span.d = Date.now() - span.ts; + span.transmit(); + throw error; + }); + } }); } @@ -175,20 +177,22 @@ function instrumentedSendBatch(ctx, originalSendBatch, originalArgs, topicMessag span.b = { s: messageCount }; } - return originalSendBatch - .apply(ctx, originalArgs) - .then(result => { - span.d = Date.now() - span.ts; - span.transmit(); - return result; - }) - .catch(error => { - span.ec = 1; - tracingUtil.setErrorDetails(span, error, 'kafka'); - span.d = Date.now() - span.ts; - span.transmit(); - throw error; - }); + const promise = originalSendBatch.apply(ctx, originalArgs); + if (typeof promise?.then === 'function') { + return promise + .then(result => { + span.d = Date.now() - span.ts; + span.transmit(); + return result; + }) + .catch(error => { + span.ec = 1; + tracingUtil.setErrorDetails(span, error, 'kafka'); + span.d = Date.now() - span.ts; + span.transmit(); + throw error; + }); + } }); } diff --git a/packages/core/src/tracing/instrumentation/protocols/nativeFetch.js b/packages/core/src/tracing/instrumentation/protocols/nativeFetch.js index 9b72e210f6..d1bf61061c 100644 --- a/packages/core/src/tracing/instrumentation/protocols/nativeFetch.js +++ b/packages/core/src/tracing/instrumentation/protocols/nativeFetch.js @@ -171,29 +171,31 @@ function instrument() { injectTraceCorrelationHeaders(originalArgs, span, w3cTraceContext); const fetchPromise = originalFetch.apply(originalThis, originalArgs); - fetchPromise - .then(response => { - span.data.http.status = response.status; - span.ec = response.status >= 500 ? 1 : 0; - capturedHeaders = mergeExtraHeadersFromFetchHeaders( - capturedHeaders, - response.headers, - extraHttpHeadersToCapture - ); - - span.d = Date.now() - span.ts; - if (capturedHeaders != null && Object.keys(capturedHeaders).length > 0) { - span.data.http.header = capturedHeaders; - } - span.transmit(); - }) - .catch(err => { - span.ec = 1; - tracingUtil.setErrorDetails(span, err, 'http'); - - span.d = Date.now() - span.ts; - span.transmit(); - }); + if (typeof fetchPromise?.then === 'function') { + fetchPromise + .then(response => { + span.data.http.status = response.status; + span.ec = response.status >= 500 ? 1 : 0; + capturedHeaders = mergeExtraHeadersFromFetchHeaders( + capturedHeaders, + response.headers, + extraHttpHeadersToCapture + ); + + span.d = Date.now() - span.ts; + if (capturedHeaders != null && Object.keys(capturedHeaders).length > 0) { + span.data.http.header = capturedHeaders; + } + span.transmit(); + }) + .catch(err => { + span.ec = 1; + tracingUtil.setErrorDetails(span, err, 'http'); + + span.d = Date.now() - span.ts; + span.transmit(); + }); + } return fetchPromise; });