Repository URL to install this package:
|
Version:
0.7.10 ▾
|
// (c) Copyright 2023 Supertenant Ltd. - all rights reserved.
// See LICENSE file in project root for license terms.
"use strict";const LRU=require("lru-cache"),shimmer=require("shimmer"),requireHook=require("../../../util/requireHook"),tracingUtil=require("../../tracingUtil"),constants=require("../../constants"),cls=require("../../cls");let isActive=!1;const preparedStatements=new LRU(1e5),connectionUriRegex=/^\s*postgres(?:ql)?:\/\/(?:([^:@]+)?(?::.+)?@)?([^:/?#]+)?(?::(\d+))?(?:\/([^?]+))?(?:\?.*)?$/;function instrumentPgNative(Client){shimmer.wrap(Client.prototype,"_awaitResult",shimAwaitResult),shimmer.wrap(Client.prototype,"connect",shimConnect),shimmer.wrap(Client.prototype,"connectSync",shimConnect),shimmer.wrap(Client.prototype,"query",shimQueryOrExecute.bind(null,instrumentedQuery)),shimmer.wrap(Client.prototype,"querySync",shimQueryOrExecuteSync.bind(null,!1)),shimmer.wrap(Client.prototype,"prepare",shimPrepare),shimmer.wrap(Client.prototype,"prepareSync",shimPrepare),shimmer.wrap(Client.prototype,"execute",shimQueryOrExecute.bind(null,instrumentedExecute)),shimmer.wrap(Client.prototype,"executeSync",shimQueryOrExecuteSync.bind(null,!0))}function shimConnect(original){return function(connectionString){connectionString=exports.parseConnectionParameters(connectionString);return 0<Object.keys(connectionString).length&&(this._instana=connectionString),original.apply(this,arguments)}}function shimAwaitResult(original){return function(){if(cls.skipExitTracing({isActive:isActive})||"function"!=typeof arguments[0])return original.apply(this,arguments);var originalArgs=new Array(arguments.length);originalArgs[0]=cls.ns.bind(arguments[0]);for(let i=1;i<arguments.length;i++)originalArgs[i]=arguments[i];return original.apply(this,originalArgs)}}function shimPrepare(original){return function(statementName,text){return preparedStatements.set(statementName,text),original.apply(this,arguments)}}function shimQueryOrExecute(instrumented,original){return function(){if(cls.skipExitTracing({isActive:isActive}))return original.apply(this,arguments);var originalArgs=new Array(arguments.length);for(let i=0;i<arguments.length;i++)originalArgs[i]=arguments[i];return instrumented(this,original,originalArgs)}}function instrumentedQuery(ctx,originalQuery,originalArgs){return startSpan(ctx,originalQuery,originalArgs,originalArgs[0])}function instrumentedExecute(ctx,originalExecute,originalArgs){return startSpan(ctx,originalExecute,originalArgs,preparedStatements.get(originalArgs[0]))}function shimQueryOrExecuteSync(isExecute,original){return function(){if(cls.skipExitTracing({isActive:isActive}))return original.apply(this,arguments);var originalArgs=new Array(arguments.length);for(let i=0;i<arguments.length;i++)originalArgs[i]=arguments[i];var statement=isExecute?preparedStatements.get(originalArgs[0]):originalArgs[0],statement=startSpanBeforeSync(this,original,originalArgs,statement);if(finishSpan(statement.error,statement.span),statement.error)throw statement.error;return statement.result}}function startSpan(ctx,originalFn,originalArgs,statement){return cls.ns.runAndReturn(()=>{const span=cls.startSpan(exports.spanName,constants.EXIT);span.data.pg={stmt:tracingUtil.shortenDatabaseStatement(statement),host:ctx._instana?ctx._instana.host:void 0,port:ctx._instana?ctx._instana.port:void 0,user:ctx._instana?ctx._instana.user:void 0,db:ctx._instana?ctx._instana.db:void 0};let originalCallback,callbackIndex=-1;for(let i=1;i<originalArgs.length;i++)if("function"==typeof originalArgs[i]){originalCallback=originalArgs[i],callbackIndex=i;break}return 0<=callbackIndex&&(originalArgs[callbackIndex]=cls.ns.bind(function(error){return finishSpan(error,span),originalCallback.apply(this,arguments)})),originalFn.apply(ctx,originalArgs)})}function startSpanBeforeSync(ctx,originalFn,originalArgs,statement){return cls.ns.runAndReturn(()=>{var span=cls.startSpan(exports.spanName,constants.EXIT);span.data.pg={stmt:tracingUtil.shortenDatabaseStatement(statement),host:ctx._instana?ctx._instana.host:void 0,port:ctx._instana?ctx._instana.port:void 0,user:ctx._instana?ctx._instana.user:void 0,db:ctx._instana?ctx._instana.db:void 0};let result,error;try{result=originalFn.apply(ctx,originalArgs)}catch(_error){error=_error}return{result:result,error:error,span:span}})}function finishSpan(error,span){error&&(span.ec=1,span.data.pg.error=tracingUtil.getErrorDetails(error)),span.d=Date.now()-span.ts,span.transmit()}function parseConnectionUri(connectionString,connectionParams){connectionString=connectionUriRegex.exec(connectionString);connectionString&&(readConnectionParamFromRegexMatch(connectionParams,connectionString,1,"user"),readConnectionParamFromRegexMatch(connectionParams,connectionString,2,"host"),readConnectionParamFromRegexMatch(connectionParams,connectionString,3,"port"),readConnectionParamFromRegexMatch(connectionParams,connectionString,4,"db"))}function readConnectionParamFromRegexMatch(connectionParams,matchResult,index,key){null!=matchResult[index]&&(connectionParams[key]=matchResult[index])}function parseKeyValueConnectionString(connectionString,connectionParams){connectionString.split(" ").map(pair=>pair.trim()).forEach(pair=>["host","hostaddr","port","dbname","user"].forEach(key=>parseConnectStringKeyValuePair(connectionParams,pair,key)))}function parseConnectStringKeyValuePair(connectionParams,pair,key){0===pair.toLowerCase().indexOf(key+"=")&&(connectionParams[key]=pair.split("=")[1])}function parseConnectionEnvVars(connectionParams){parseEnvVar(connectionParams,"PGHOST","host"),parseEnvVar(connectionParams,"PGHOSTADDR","hostaddr"),parseEnvVar(connectionParams,"PGPORT","port"),parseEnvVar(connectionParams,"PGDATABASE","db"),parseEnvVar(connectionParams,"PGUSER","user")}function parseEnvVar(connectionParams,keyEnvVar,keyConnectionParams){process.env[keyEnvVar]&&(connectionParams[keyConnectionParams]=process.env[keyEnvVar])}exports.spanName="postgres",exports.batchable=!0,exports.init=function(){requireHook.onModuleLoad("pg-native",instrumentPgNative)},exports.parseConnectionParameters=function(connectionString){var connectionParams={};return"string"==typeof connectionString?(0===(connectionString=connectionString.trim()).indexOf("postgres")?parseConnectionUri:parseKeyValueConnectionString)(connectionString,connectionParams):parseConnectionEnvVars(connectionParams),connectionParams.hostaddr&&!connectionParams.host&&(connectionParams.host=connectionParams.hostaddr),delete connectionParams.hostaddr,connectionParams.dbname&&(connectionParams.db=connectionParams.dbname,delete connectionParams.dbname),connectionParams},exports.activate=function(){isActive=!0},exports.deactivate=function(){isActive=!1};