Repository URL to install this package:
|
Version:
0.7.0 ▾
|
// (c) Copyright 2023 Supertenant Ltd. - all rights reserved.
// See LICENSE file in project root for license terms.
"use strict";const shimmer=require("shimmer"),requireHook=require("../../../util/requireHook"),tracingUtil=require("../../tracingUtil"),constants=require("../../constants"),cls=require("../../cls");let isActive=!1,connectionStr;const CLOSE_TIMEOUT_IN_MS=process.env.DB2_CLOSE_TIMEOUT_IN_MS||3e4;function instrument(db2){shimmer.wrap(db2.Database.prototype,"open",instrumentOpen),shimmer.wrap(db2.Database.prototype,"openSync",instrumentOpen),shimmer.wrap(db2.Database.prototype,"query",instrumentQuery),shimmer.wrap(db2.Database.prototype,"querySync",instrumentQuerySync),shimmer.wrap(db2.Database.prototype,"queryResult",instrumentQueryResult),shimmer.wrap(db2.Database.prototype,"queryResultSync",instrumentQueryResultSync),shimmer.wrap(db2.Database.prototype,"beginTransaction",instrumentBeginTransaction),shimmer.wrap(db2.Database.prototype,"prepare",instrumentPrepare),shimmer.wrap(db2.Database.prototype,"prepareSync",instrumentPrepareSync)}function skipTracing(ignoreClsTracing=!1){return cls.skipExitTracing({isActive:isActive,skipIsTracing:!0,skipParentSpanCheck:!0})||!ignoreClsTracing&&!cls.isTracing()}function instrumentOpen(originalFunction){return function(){return connectionStr=arguments[0],originalFunction.apply(this,arguments)}}function instrumentQueryResult(originalFunction){return function(stmt){return instrumentQueryResultHelper(this,arguments,originalFunction,stmt,!0)}}function instrumentQueryResultSync(originalFunction){return function(stmt){return instrumentQueryResultHelper(this,arguments,originalFunction,stmt,!1)}}function instrumentBeginTransaction(originalFunction){return function(){const parentSpan=cls.getCurrentSpan(),originalCallback=arguments[0];return("function"!=typeof originalCallback?originalCallback:(arguments[0]=cls.ns.bind(function(){return cls.setCurrentSpan(parentSpan),originalCallback.apply(this,arguments)}),originalFunction)).apply(this,arguments)}}function instrumentQuery(originalFunction){return function(stmt){return instrumentQueryHelper(this,arguments,originalFunction,stmt,!0)}}function instrumentQuerySync(originalFunction){return function(stmt){return instrumentQueryHelper(this,arguments,originalFunction,stmt,!1)}}function instrumentPrepare(originalFunction){return function(){const ctx=this,originalArgs=arguments,possibleParentSpan=cls.getCurrentEntrySpan(),originalCallback=originalArgs[1];return"function"==typeof originalCallback&&(originalArgs[1]=function(err,stmtObject){return err||instrumentExecuteHelper(ctx,originalArgs,stmtObject,possibleParentSpan),originalCallback.apply(this,arguments)}),originalFunction.apply(this,originalArgs)}}function instrumentPrepareSync(originalFunction){return function(){var originalArgs=arguments,possibleParentSpan=cls.getCurrentEntrySpan(),stmtObject=originalFunction.apply(this,originalArgs);return stmtObject instanceof Error||instrumentExecuteHelper(this,originalArgs,stmtObject,possibleParentSpan),stmtObject}}function captureFetchError(result,span){result&&(["fetch","fetchAll"].forEach(fnName=>{if(result[fnName]){const originalFn=result[fnName];result[fnName]=function(){var argsFetch=arguments,fetchIndex=1===argsFetch.length&&"function"==typeof argsFetch[0]?0:2===argsFetch.length&&"function"==typeof argsFetch[1]?1:null;const fetchCb=argsFetch[fetchIndex];argsFetch[fetchIndex]=function(fetchCbErr){return fetchCbErr&&(span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(fetchCbErr)),fetchCb.apply(this,arguments)};try{return originalFn.apply(this,arguments)}catch(caughtErr){throw span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(caughtErr),caughtErr}}}}),["fetchSync","fetchAllSync"].forEach(fnName=>{if(result[fnName]){const originalFn=result[fnName];result[fnName]=function(){try{var res=originalFn.apply(this,arguments);return res instanceof Error&&(span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(res)),res}catch(err){return span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(err),err}}}}))}function instrumentQueryHelper(ctx,originalArgs,originalFunction,stmt,isAsync){return skipTracing()?originalFunction.apply(ctx,originalArgs):cls.ns.runAndReturn(()=>{const span=createSpan(stmt,instrumentQueryHelper);if(!isAsync)try{var result=originalFunction.apply(ctx,originalArgs);return result instanceof Error&&(span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(result)),finishSpan(ctx,result,span),result}catch(e){throw span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(e),finishSpan(ctx,null,span),e}var result=2===originalArgs.length&&"function"==typeof originalArgs[1]?1:3===originalArgs.length&&"function"==typeof originalArgs[2]?2:null;const customerCallback=null!=result?originalArgs[result]:null;return customerCallback?(originalArgs[result]=function(err){return err&&(span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(err)),finishSpan(ctx,null,span),customerCallback.apply(this,arguments)},originalFunction.apply(ctx,originalArgs)):(result=originalFunction.apply(ctx,originalArgs))&&"function"==typeof result.then&&"function"==typeof result.catch?(result.then(result=>(finishSpan(ctx,result,span),result)).catch(err=>(span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(err),finishSpan(ctx,null,span),err)),result):void 0})}function instrumentExecuteHelper(ctx,originalArgs,stmtObject,prepareCallParentSpan){let rememberedParentSpan;const canTrace=()=>{var parentSpan=cls.getCurrentSpan()||prepareCallParentSpan;return!constants.isExitSpan(parentSpan)&&(parentSpan||(rememberedParentSpan=rememberedParentSpan||parentSpan),!skipTracing(!parentSpan||!!prepareCallParentSpan))&&(cls.setCurrentSpan(rememberedParentSpan||parentSpan),!0)},originalExecuteNonQuerySync=stmtObject.executeNonQuerySync,originalExecuteSync=(stmtObject.executeNonQuerySync=function(){return cls.ns.runAndReturn(()=>{if(!canTrace())return originalExecuteNonQuerySync.apply(this,arguments);var span=createSpan(originalArgs[0],instrumentExecuteHelper);try{var result=originalExecuteNonQuerySync.apply(this,arguments);return finishSpan(ctx,result,span),result}catch(err){return span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(err),finishSpan(ctx,null,span),err}})},stmtObject.executeSync),originalExecute=(stmtObject.executeSync=function(){return cls.ns.runAndReturn(()=>{var span,result;return canTrace()?(span=createSpan(originalArgs[0],instrumentExecuteHelper),result=originalExecuteSync.apply(this,arguments),finishSpan(ctx,result,span),result):originalExecuteSync.apply(this,arguments)})},stmtObject.execute);stmtObject.execute=function(){return cls.ns.runAndReturn(()=>{if(canTrace()){const span=createSpan(originalArgs[0],instrumentExecuteHelper);var args=arguments,origCallbackIndex=1===args.length&&"function"==typeof args[0]?0:2===args.length&&"function"==typeof args[1]?1:null;const origCallback=args[origCallbackIndex];args[origCallbackIndex]=function(executeErr,result){return executeErr?(span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(executeErr),finishSpan(ctx,null,span)):finishSpan(ctx,result,span),origCallback.apply(this,arguments)}}return originalExecute.apply(this,arguments)})}}function instrumentQueryResultHelper(ctx,originalArgs,originalFunction,stmt,isAsync){return skipTracing()?originalFunction.apply(ctx,originalArgs):cls.ns.runAndReturn(()=>{const span=createSpan(stmt,instrumentQueryResultHelper);if(!isAsync)try{var result=originalFunction.apply(ctx,originalArgs);return finishSpan(ctx,result,span),result}catch(err){return span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(err),finishSpan(ctx,null,span),err}result=2===originalArgs.length&&"function"==typeof originalArgs[1]?1:3===originalArgs.length&&"function"==typeof originalArgs[2]?2:null;const customerCallback=null!=result?originalArgs[result]:null;if(customerCallback)return originalArgs[result]=function(err){err&&(span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(err));err=customerCallback.apply(this,arguments);return finishSpan(ctx,err,span),err},originalFunction.apply(ctx,originalArgs)})}function createSpan(stmt,fn){var span=cls.startSpan(exports.spanName,constants.EXIT);return span.stack=tracingUtil.getStackTrace(fn),span.ts=Date.now(),span.data.db2={stmt:tracingUtil.shortenDatabaseStatement(stmt),dsn:tracingUtil.sanitizeConnectionStr(connectionStr)},span}function finishSpan(ctx,result,span){if(captureFetchError(result,span),ctx.conn.inTransaction)return handleTransaction(ctx,span);if(result&&result.closeSync){const originalCloseSync=result.closeSync;let closeSyncCalled=!1;result.closeSync=function(){return closeSyncCalled||(closeSyncCalled=!0,span.d=Date.now()-span.ts,span.transmit()),originalCloseSync.apply(this,arguments)},setTimeout(()=>{closeSyncCalled||(closeSyncCalled=!0,span.ec=1,span.data.db2.error=`'result.closeSync' was not called within ${CLOSE_TIMEOUT_IN_MS}ms.`,span.d=Date.now()-span.ts,span.transmit())},CLOSE_TIMEOUT_IN_MS).unref()}else span.d=Date.now()-span.ts,span.transmit()}function handleTransaction(ctx,span){["endTransaction","endTransactionSync"].forEach(fn=>{const originalFn=ctx.conn[fn];"function"==typeof originalFn&&(ctx.conn[fn]=function(){const originalOnEndCallback=arguments[1];if("function"==typeof originalOnEndCallback)return arguments[1]=function(onEndErr){return onEndErr&&(span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(onEndErr)||"Error not available."),span.d=Date.now()-span.ts,span.transmit(),originalOnEndCallback.apply(this,arguments)},originalFn.apply(this,arguments);try{var result=originalFn.apply(this,arguments);return span.d=Date.now()-span.ts,span.transmit(),result}catch(err){throw span.ec=1,span.data.db2.error=tracingUtil.getErrorDetails(err)||"Error not available.",span.transmit(),err}})})}exports.spanName="db2",exports.init=function(){requireHook.onModuleLoad("ibm_db",instrument)},exports.activate=function(){isActive=!0},exports.deactivate=function(){isActive=!1};