diff --git a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION index 28cbf7c0aa..1a487e1a2e 100644 --- a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION +++ b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/VERSION @@ -1 +1 @@ -5.0.0 \ No newline at end of file +5.0.0-beta2 \ No newline at end of file diff --git a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/api.ts index 4d188b2da3..55844bd813 100644 --- a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -531,7 +531,6 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati if (configuration) { baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -540,23 +539,18 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati localVarHeaderParameter['Content-Type'] = 'application/json'; - const queryParameters = new URLSearchParams(localVarUrlObj.search); + const query = new URLSearchParams(localVarUrlObj.search); for (const key in localVarQueryParameter) { - queryParameters.set(key, localVarQueryParameter[key]); + query.set(key, localVarQueryParameter[key]); } for (const key in options.query) { - queryParameters.set(key, options.query[key]); + query.set(key, options.query[key]); } - localVarUrlObj.search = (new URLSearchParams(queryParameters)).toString(); + localVarUrlObj.search = (new URLSearchParams(query)).toString(); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - const nonString = typeof deployContractSolidityBytecodeV1Request !== 'string'; - const needsSerialization = nonString && configuration && configuration.isJsonMime - ? configuration.isJsonMime(localVarRequestOptions.headers['Content-Type']) - : nonString; - localVarRequestOptions.data = needsSerialization - ? JSON.stringify(deployContractSolidityBytecodeV1Request !== undefined ? deployContractSolidityBytecodeV1Request : {}) - : (deployContractSolidityBytecodeV1Request || ""); + const needsSerialization = (typeof deployContractSolidityBytecodeV1Request !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(deployContractSolidityBytecodeV1Request !== undefined ? deployContractSolidityBytecodeV1Request : {}) : (deployContractSolidityBytecodeV1Request || ""); return { url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, @@ -578,7 +572,6 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati if (configuration) { baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -587,23 +580,18 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati localVarHeaderParameter['Content-Type'] = 'application/json'; - const queryParameters = new URLSearchParams(localVarUrlObj.search); + const query = new URLSearchParams(localVarUrlObj.search); for (const key in localVarQueryParameter) { - queryParameters.set(key, localVarQueryParameter[key]); + query.set(key, localVarQueryParameter[key]); } for (const key in options.query) { - queryParameters.set(key, options.query[key]); + query.set(key, options.query[key]); } - localVarUrlObj.search = (new URLSearchParams(queryParameters)).toString(); + localVarUrlObj.search = (new URLSearchParams(query)).toString(); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - const nonString = typeof invokeContractV1Request !== 'string'; - const needsSerialization = nonString && configuration && configuration.isJsonMime - ? configuration.isJsonMime(localVarRequestOptions.headers['Content-Type']) - : nonString; - localVarRequestOptions.data = needsSerialization - ? JSON.stringify(invokeContractV1Request !== undefined ? invokeContractV1Request : {}) - : (invokeContractV1Request || ""); + const needsSerialization = (typeof invokeContractV1Request !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(invokeContractV1Request !== undefined ? invokeContractV1Request : {}) : (invokeContractV1Request || ""); return { url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, @@ -625,7 +613,6 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati if (configuration) { baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -634,23 +621,18 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati localVarHeaderParameter['Content-Type'] = 'application/json'; - const queryParameters = new URLSearchParams(localVarUrlObj.search); + const query = new URLSearchParams(localVarUrlObj.search); for (const key in localVarQueryParameter) { - queryParameters.set(key, localVarQueryParameter[key]); + query.set(key, localVarQueryParameter[key]); } for (const key in options.query) { - queryParameters.set(key, options.query[key]); + query.set(key, options.query[key]); } - localVarUrlObj.search = (new URLSearchParams(queryParameters)).toString(); + localVarUrlObj.search = (new URLSearchParams(query)).toString(); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - const nonString = typeof runTransactionRequest !== 'string'; - const needsSerialization = nonString && configuration && configuration.isJsonMime - ? configuration.isJsonMime(localVarRequestOptions.headers['Content-Type']) - : nonString; - localVarRequestOptions.data = needsSerialization - ? JSON.stringify(runTransactionRequest !== undefined ? runTransactionRequest : {}) - : (runTransactionRequest || ""); + const needsSerialization = (typeof runTransactionRequest !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(runTransactionRequest !== undefined ? runTransactionRequest : {}) : (runTransactionRequest || ""); return { url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, @@ -676,7 +658,6 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati if (configuration) { baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -685,23 +666,18 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati localVarHeaderParameter['Content-Type'] = 'application/json'; - const queryParameters = new URLSearchParams(localVarUrlObj.search); + const query = new URLSearchParams(localVarUrlObj.search); for (const key in localVarQueryParameter) { - queryParameters.set(key, localVarQueryParameter[key]); + query.set(key, localVarQueryParameter[key]); } for (const key in options.query) { - queryParameters.set(key, options.query[key]); + query.set(key, options.query[key]); } - localVarUrlObj.search = (new URLSearchParams(queryParameters)).toString(); + localVarUrlObj.search = (new URLSearchParams(query)).toString(); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - const nonString = typeof signTransactionRequest !== 'string'; - const needsSerialization = nonString && configuration && configuration.isJsonMime - ? configuration.isJsonMime(localVarRequestOptions.headers['Content-Type']) - : nonString; - localVarRequestOptions.data = needsSerialization - ? JSON.stringify(signTransactionRequest !== undefined ? signTransactionRequest : {}) - : (signTransactionRequest || ""); + const needsSerialization = (typeof signTransactionRequest !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(signTransactionRequest !== undefined ? signTransactionRequest : {}) : (signTransactionRequest || ""); return { url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, @@ -727,7 +703,7 @@ export const DefaultApiFp = function(configuration?: Configuration) { async apiV1BesuDeployContractSolidityBytecode(deployContractSolidityBytecodeV1Request?: DeployContractSolidityBytecodeV1Request, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await DefaultApiAxiosParamCreator(configuration).apiV1BesuDeployContractSolidityBytecode(deployContractSolidityBytecodeV1Request, options); return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { - const axiosRequestArgs = {...localVarAxiosArgs.options, url: (configuration?.basePath || basePath) + localVarAxiosArgs.url}; + const axiosRequestArgs = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; return axios.request(axiosRequestArgs); }; }, @@ -741,7 +717,7 @@ export const DefaultApiFp = function(configuration?: Configuration) { async apiV1BesuInvokeContract(invokeContractV1Request?: InvokeContractV1Request, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await DefaultApiAxiosParamCreator(configuration).apiV1BesuInvokeContract(invokeContractV1Request, options); return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { - const axiosRequestArgs = {...localVarAxiosArgs.options, url: (configuration?.basePath || basePath) + localVarAxiosArgs.url}; + const axiosRequestArgs = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; return axios.request(axiosRequestArgs); }; }, @@ -755,7 +731,7 @@ export const DefaultApiFp = function(configuration?: Configuration) { async apiV1BesuRunTransaction(runTransactionRequest?: RunTransactionRequest, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await DefaultApiAxiosParamCreator(configuration).apiV1BesuRunTransaction(runTransactionRequest, options); return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { - const axiosRequestArgs = {...localVarAxiosArgs.options, url: (configuration?.basePath || basePath) + localVarAxiosArgs.url}; + const axiosRequestArgs = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; return axios.request(axiosRequestArgs); }; }, @@ -769,7 +745,7 @@ export const DefaultApiFp = function(configuration?: Configuration) { async signTransactionV1(signTransactionRequest: SignTransactionRequest, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { const localVarAxiosArgs = await DefaultApiAxiosParamCreator(configuration).signTransactionV1(signTransactionRequest, options); return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { - const axiosRequestArgs = {...localVarAxiosArgs.options, url: (configuration?.basePath || basePath) + localVarAxiosArgs.url}; + const axiosRequestArgs = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; return axios.request(axiosRequestArgs); }; }, diff --git a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/configuration.ts b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/configuration.ts index 64dbb46b9b..15244eaa83 100644 --- a/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/configuration.ts +++ b/packages/cactus-plugin-ledger-connector-besu/src/main/typescript/generated/openapi/typescript-axios/configuration.ts @@ -20,7 +20,6 @@ export interface ConfigurationParameters { accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); basePath?: string; baseOptions?: any; - formDataCtor?: new () => any; } export class Configuration { @@ -65,14 +64,6 @@ export class Configuration { * @memberof Configuration */ baseOptions?: any; - /** - * The FormData constructor that will be used to create multipart form data - * requests. You can inject this here so that execution environments that - * do not support the FormData class can still run the generated client. - * - * @type {new () => FormData} - */ - formDataCtor?: new () => any; constructor(param: ConfigurationParameters = {}) { this.apiKey = param.apiKey; @@ -81,21 +72,5 @@ export class Configuration { this.accessToken = param.accessToken; this.basePath = param.basePath; this.baseOptions = param.baseOptions; - this.formDataCtor = param.formDataCtor; - } - - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); } } diff --git a/packages/cactus-plugin-ledger-connector-fabric/package-lock.json b/packages/cactus-plugin-ledger-connector-fabric/package-lock.json index 223a603556..ceb25bf024 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/package-lock.json +++ b/packages/cactus-plugin-ledger-connector-fabric/package-lock.json @@ -374,6 +374,11 @@ "file-uri-to-path": "1.0.0" } }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, "bip66": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", @@ -1831,7 +1836,8 @@ "follow-redirects": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", - "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==" + "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==", + "dev": true }, "forever-agent": { "version": "0.6.1", @@ -3291,6 +3297,14 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "prom-client": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.0.0.tgz", + "integrity": "sha512-M7ZNjIO6x+2R/vjSD13yjJPjpoZA8eEwH2Bp2Re0/PvzozD7azikv+SaBtZes4Q1ca/xHjZ4RSCuTag3YZLg1A==", + "requires": { + "tdigest": "^0.1.1" + } + }, "promise-settle": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/promise-settle/-/promise-settle-0.3.0.tgz", @@ -3905,6 +3919,14 @@ } } }, + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, "temp": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.1.tgz", @@ -4224,6 +4246,7 @@ "resolved": "https://registry.npmjs.org/web3-eea/-/web3-eea-0.9.0.tgz", "integrity": "sha512-QCtwos4DVdvw+NhfIKi3/sLs3sVfO2q5Xw/6wQooHkqoIT/O8/0x6YbR2+OUpV2bdcvuowWOxA0JJ9K/mFGF7A==", "requires": { + "axios": "0.19.2", "ethereumjs-tx": "1.3.7", "ethereumjs-util": "6.1.0", "lodash": "4.17.15", @@ -4237,11 +4260,29 @@ "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==" }, "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + }, + "dependencies": { + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + } + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { - "follow-redirects": "^1.10.0" + "ms": "2.0.0" } }, "ethereumjs-tx": { diff --git a/packages/cactus-plugin-ledger-connector-fabric/package.json b/packages/cactus-plugin-ledger-connector-fabric/package.json index 79e126559c..4949b44991 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/package.json +++ b/packages/cactus-plugin-ledger-connector-fabric/package.json @@ -12,7 +12,7 @@ "dist/*" ], "scripts": { - "generate-sdk": "openapi-generator generate --input-spec src/main/json/openapi.json -g typescript-axios -o ./src/main/typescript/generated/openapi/typescript-axios/ --reserved-words-mappings protected=protected", + "generate-sdk": "openapi-generator generate --input-spec src/main/json/openapi.json -g typescript-axios -o ./src/main/typescript/generated/openapi/typescript-axios/ --reserved-words-mappings protected=protected --type-mappings=DateTime=Date", "pretsc": "npm run generate-sdk", "tsc": "tsc --project ./tsconfig.json", "watch": "npm-watch", @@ -95,6 +95,7 @@ "ngo": "2.6.2", "node-ssh": "11.0.0", "openapi-types": "7.0.1", + "prom-client": "13.0.0", "temp": "0.9.1", "typescript-optional": "2.0.1", "uuid": "8.3.0", diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/json/openapi.json b/packages/cactus-plugin-ledger-connector-fabric/src/main/json/openapi.json index 7865982525..046a07fdc2 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/main/json/openapi.json +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/json/openapi.json @@ -286,6 +286,69 @@ "type": "string" } } + }, + "Transaction": { + "type": "object", + "required": [ + "startTime", + "endTime" + ], + "properties": { + "startTime":{ + "format": "date-time", + "type": "string" + }, + "endTime":{ + "format": "date-time", + "type": "string" + } + } + }, + "Transactions": { + "type": "array", + "items":{ + "$ref": "#/components/schemas/Transaction" + } + }, + "PrometheusExporter": { + "type": "object", + "required": [ + "metricsPollingIntervalInMin" + ], + "properties": { + "metricsPollingIntervalInMin": { + "description": "The polling interval for the prometheus exporter (in minutes)", + "type": "number", + "nullable": false + }, + "transactions":{ + "description": "The transcation queue", + "$ref": "#/components/schemas/Transactions" + } + } + }, + "PrometheusExporterMetricsRequest": { + "type": "object", + "required": [ + "promExporter" + ], + "properties": { + "promExporter":{ + "description": "The prometheus exporter class object", + "$ref": "#/components/schemas/PrometheusExporter" + } + } + }, + "PrometheusExporterMetricsResponse": { + "type": "object", + "required": [ + "result" + ], + "properties": { + "result": { + "type": "string" + } + } } } }, @@ -368,6 +431,40 @@ } } } + }, + "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-fabric/get-prometheus-exporter-metrics": { + "get": { + "x-hyperledger-cactus": { + "http": { + "verbLowerCase": "get", + "path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-fabric/get-prometheus-exporter-metrics" + } + }, + "operationId": "getPrometheusExporterMetricsV1", + "summary": "Get the Prometheus Metrics", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrometheusExporterMetricsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrometheusExporterMetricsResponse" + } + } + } + } + } + } } } } \ No newline at end of file diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore index 6a6325b75c..ecd97ff37f 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator-ignore @@ -24,3 +24,4 @@ git_push.sh .npmignore +.gitignore \ No newline at end of file diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES index 565ea4915d..c123dd7d45 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/.openapi-generator/FILES @@ -1,4 +1,3 @@ -.gitignore api.ts base.ts configuration.ts diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/api.ts index 248eb444b3..2330ec5557 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -243,6 +243,51 @@ export interface InlineResponse501 { */ message?: string; } +/** + * + * @export + * @interface PrometheusExporter + */ +export interface PrometheusExporter { + /** + * The polling interval for the prometheus exporter (in minutes) + * @type {number} + * @memberof PrometheusExporter + */ + metricsPollingIntervalInMin: number; + /** + * + * @type {Array} + * @memberof PrometheusExporter + */ + transactions?: Array; +} +/** + * + * @export + * @interface PrometheusExporterMetricsRequest + */ +export interface PrometheusExporterMetricsRequest { + /** + * + * @type {PrometheusExporter} + * @memberof PrometheusExporterMetricsRequest + */ + promExporter: PrometheusExporter; +} +/** + * + * @export + * @interface PrometheusExporterMetricsResponse + */ +export interface PrometheusExporterMetricsResponse { + /** + * + * @type {string} + * @memberof PrometheusExporterMetricsResponse + */ + result: string; +} /** * * @export @@ -305,6 +350,25 @@ export interface RunTransactionResponse { */ functionOutput: string; } +/** + * + * @export + * @interface Transaction + */ +export interface Transaction { + /** + * + * @type {Date} + * @memberof Transaction + */ + startTime: Date; + /** + * + * @type {Date} + * @memberof Transaction + */ + endTime: Date; +} /** * DefaultApi - axios parameter creator @@ -353,6 +417,47 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati options: localVarRequestOptions, }; }, + /** + * + * @summary Get the Prometheus Metrics + * @param {PrometheusExporterMetricsRequest} [prometheusExporterMetricsRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getPrometheusExporterMetricsV1: async (prometheusExporterMetricsRequest?: PrometheusExporterMetricsRequest, options: any = {}): Promise => { + const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-fabric/get-prometheus-exporter-metrics`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, 'https://example.com'); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + const query = new URLSearchParams(localVarUrlObj.search); + for (const key in localVarQueryParameter) { + query.set(key, localVarQueryParameter[key]); + } + for (const key in options.query) { + query.set(key, options.query[key]); + } + localVarUrlObj.search = (new URLSearchParams(query)).toString(); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + const needsSerialization = (typeof prometheusExporterMetricsRequest !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json'; + localVarRequestOptions.data = needsSerialization ? JSON.stringify(prometheusExporterMetricsRequest !== undefined ? prometheusExporterMetricsRequest : {}) : (prometheusExporterMetricsRequest || ""); + + return { + url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash, + options: localVarRequestOptions, + }; + }, /** * * @summary Runs a transaction on a Fabric ledger. @@ -421,6 +526,20 @@ export const DefaultApiFp = function(configuration?: Configuration) { return axios.request(axiosRequestArgs); }; }, + /** + * + * @summary Get the Prometheus Metrics + * @param {PrometheusExporterMetricsRequest} [prometheusExporterMetricsRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getPrometheusExporterMetricsV1(prometheusExporterMetricsRequest?: PrometheusExporterMetricsRequest, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await DefaultApiAxiosParamCreator(configuration).getPrometheusExporterMetricsV1(prometheusExporterMetricsRequest, options); + return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url}; + return axios.request(axiosRequestArgs); + }; + }, /** * * @summary Runs a transaction on a Fabric ledger. @@ -454,6 +573,16 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa deployContractGoSourceV1(deployContractGoSourceV1Request?: DeployContractGoSourceV1Request, options?: any): AxiosPromise { return DefaultApiFp(configuration).deployContractGoSourceV1(deployContractGoSourceV1Request, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Get the Prometheus Metrics + * @param {PrometheusExporterMetricsRequest} [prometheusExporterMetricsRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getPrometheusExporterMetricsV1(prometheusExporterMetricsRequest?: PrometheusExporterMetricsRequest, options?: any): AxiosPromise { + return DefaultApiFp(configuration).getPrometheusExporterMetricsV1(prometheusExporterMetricsRequest, options).then((request) => request(axios, basePath)); + }, /** * * @summary Runs a transaction on a Fabric ledger. @@ -486,6 +615,18 @@ export class DefaultApi extends BaseAPI { return DefaultApiFp(this.configuration).deployContractGoSourceV1(deployContractGoSourceV1Request, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Get the Prometheus Metrics + * @param {PrometheusExporterMetricsRequest} [prometheusExporterMetricsRequest] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getPrometheusExporterMetricsV1(prometheusExporterMetricsRequest?: PrometheusExporterMetricsRequest, options?: any) { + return DefaultApiFp(this.configuration).getPrometheusExporterMetricsV1(prometheusExporterMetricsRequest, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Runs a transaction on a Fabric ledger. diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/get-prometheus-exporter-metrics/get-prometheus-exporter-metrics-v1.ts b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/get-prometheus-exporter-metrics/get-prometheus-exporter-metrics-v1.ts new file mode 100644 index 0000000000..8a2bf34a27 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/get-prometheus-exporter-metrics/get-prometheus-exporter-metrics-v1.ts @@ -0,0 +1,91 @@ +import { Express, Request, Response } from "express"; + +import { + Logger, + LoggerProvider, + LogLevelDesc, + Checks, +} from "@hyperledger/cactus-common"; + +import { + IWebServiceEndpoint, + IExpressRequestHandler, +} from "@hyperledger/cactus-core-api"; + +import OAS from "../../json/openapi.json"; + +import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; + +import { PluginLedgerConnectorFabric } from "../plugin-ledger-connector-fabric"; +import { PrometheusExporter } from "../prometheus-exporter/prometheus-exporter"; + +export interface IGetPrometheusExporterMetricsV1Options { + logLevel?: LogLevelDesc; + connector: PluginLedgerConnectorFabric; +} + +export class GetPrometheusExporterMetricsV1 implements IWebServiceEndpoint { + private readonly log: Logger; + + constructor(public readonly opts: IGetPrometheusExporterMetricsV1Options) { + const fnTag = "GetPrometheusExporterMetricsV1#constructor()"; + + Checks.truthy(opts, `${fnTag} options`); + Checks.truthy(opts.connector, `${fnTag} options.connector`); + + this.log = LoggerProvider.getOrCreate({ + label: "get-prometheus-exporter-metrics-v1", + level: opts.logLevel || "INFO", + }); + } + + public getExpressRequestHandler(): IExpressRequestHandler { + return this.handleRequest.bind(this); + } + + public getPath(): string { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-fabric/get-prometheus-exporter-metrics" + ].get["x-hyperledger-cactus"].http.path; + } + + public getVerbLowerCase(): string { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-fabric/get-prometheus-exporter-metrics" + ].get["x-hyperledger-cactus"].http.verbLowerCase; + } + + public registerExpress(app: Express): IWebServiceEndpoint { + registerWebServiceEndpoint(app, this); + return this; + } + + async handleRequest(req: Request, res: Response): Promise { + const fnTag = "GetPrometheusExporterMetrics#handleRequest()"; + this.log.debug(`POST ${this.getPath()}`); + + try { + let prometheusExporterObject: PrometheusExporter = new PrometheusExporter( + { + pollingIntervalInMin: + req.body.promExporter.prometheusExporterOptions + .pollingIntervalInMin, + }, + ); + prometheusExporterObject = Object.assign( + prometheusExporterObject, + req.body.promExporter, + ); + const resBody = await this.opts.connector.getPrometheusExporterMetrics({ + promExporter: prometheusExporterObject, + }); + res.status(200); + res.json(resBody); + } catch (ex) { + this.log.error(`${fnTag} failed to serve request`, ex); + res.status(500); + res.statusMessage = ex.message; + res.json({ error: ex.stack }); + } + } +} diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts index 9e108ebaa9..cecae02837 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/plugin-ledger-connector-fabric.ts @@ -39,6 +39,11 @@ import { RunTransactionEndpointV1, } from "./run-transaction/run-transaction-endpoint-v1"; +import { + IGetPrometheusExporterMetricsV1Options, + GetPrometheusExporterMetricsV1, +} from "./get-prometheus-exporter-metrics/get-prometheus-exporter-metrics-v1"; + import { ConnectionProfile, GatewayDiscoveryOptions, @@ -48,6 +53,8 @@ import { FabricContractInvocationType, RunTransactionRequest, RunTransactionResponse, + PrometheusExporterMetricsRequest, + PrometheusExporterMetricsResponse, } from "./generated/openapi/typescript-axios/index"; import { @@ -55,12 +62,15 @@ import { IDeployContractGoSourceEndpointV1Options, } from "./deploy-contract-go-source/deploy-contract-go-source-endpoint-v1"; +import { PrometheusExporter } from "./prometheus-exporter/prometheus-exporter"; + export interface IPluginLedgerConnectorFabricOptions extends ICactusPluginOptions { logLevel?: LogLevelDesc; pluginRegistry: PluginRegistry; sshConfig: SshConfig; connectionProfile: ConnectionProfile; + prometheusExporter?: PrometheusExporter; discoveryOptions?: GatewayDiscoveryOptions; eventHandlerOptions?: GatewayEventHandlerOptions; } @@ -78,6 +88,7 @@ export class PluginLedgerConnectorFabric public static readonly CLASS_NAME = "PluginLedgerConnectorFabric"; private readonly instanceId: string; private readonly log: Logger; + public prometheusExporter: PrometheusExporter; public get className(): string { return PluginLedgerConnectorFabric.CLASS_NAME; @@ -89,11 +100,17 @@ export class PluginLedgerConnectorFabric Checks.truthy(opts.instanceId, `${fnTag} options.instanceId`); Checks.truthy(opts.pluginRegistry, `${fnTag} options.pluginRegistry`); Checks.truthy(opts.connectionProfile, `${fnTag} options.connectionProfile`); + this.prometheusExporter = + opts.prometheusExporter || + new PrometheusExporter({ pollingIntervalInMin: 1 }); + Checks.truthy( + this.prometheusExporter, + `${fnTag} options.prometheusExporter`, + ); const level = this.opts.logLevel || "INFO"; const label = this.className; this.log = LoggerProvider.getOrCreate({ level, label }); - this.instanceId = opts.instanceId; } @@ -101,6 +118,23 @@ export class PluginLedgerConnectorFabric throw new Error("Method not implemented."); } + public getPrometheusExporter(): PrometheusExporter { + return this.prometheusExporter; + } + + public startPrometheusExporterMetricsCollection(): NodeJS.Timeout { + return this.prometheusExporter.startMetricsCollection(); + } + + public async getPrometheusExporterMetrics( + req: PrometheusExporterMetricsRequest, + ): Promise { + const { promExporter } = req; + const res: PrometheusExporterMetricsResponse = await (promExporter as PrometheusExporter).getPrometheusMetrics(); + this.log.debug(`getPrometheusExporterMetrics() response: %o`, res); + return res; + } + public getInstanceId(): string { return this.instanceId; } @@ -165,6 +199,16 @@ export class PluginLedgerConnectorFabric endpoints.push(endpoint); } + { + const opts: IGetPrometheusExporterMetricsV1Options = { + connector: this, + logLevel: this.opts.logLevel, + }; + const endpoint = new GetPrometheusExporterMetricsV1(opts); + endpoint.registerExpress(expressApp); + endpoints.push(endpoint); + } + const pkg = this.getPackageName(); log.info(`Installed web services for plugin ${pkg} OK`, { endpoints }); @@ -176,6 +220,8 @@ export class PluginLedgerConnectorFabric ): Promise { const fnTag = `${this.className}#transact()`; + const startTransactionTime = new Date(); + const { connectionProfile } = this.opts; const { keychainId, @@ -243,6 +289,12 @@ export class PluginLedgerConnectorFabric functionOutput: outUtf8, }; this.log.debug(`transact() response: %o`, res); + const endTransactionTime = new Date(); + this.prometheusExporter.addCurrentTransaction( + startTransactionTime, + endTransactionTime, + ); + return res; } catch (ex) { this.log.error(`transact() crashed: `, ex); diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/data-fetcher.ts b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/data-fetcher.ts new file mode 100644 index 0000000000..7a0a59ca71 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/data-fetcher.ts @@ -0,0 +1,7 @@ +import { Transactions } from "./response.type"; + +import { totalTxCount } from "./metrics"; + +export async function collectMetrics(transactions: Transactions) { + totalTxCount.labels("totalTxCount").set(transactions.length); +} diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/metrics.ts b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/metrics.ts new file mode 100644 index 0000000000..e92ab1c628 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/metrics.ts @@ -0,0 +1,7 @@ +import { Gauge } from "prom-client"; + +export const totalTxCount = new Gauge({ + name: "totalTxCount", + help: "Total transactions executed", + labelNames: ["type"], +}); diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/prometheus-exporter.ts b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/prometheus-exporter.ts new file mode 100644 index 0000000000..13e3fca998 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/prometheus-exporter.ts @@ -0,0 +1,51 @@ +import promClient from "prom-client"; +import { Transaction, Transactions } from "./response.type"; +import { collectMetrics } from "./data-fetcher"; +import { PrometheusExporterMetricsResponse } from "../generated/openapi/typescript-axios"; + +export interface PrometheusExporterOptions { + pollingIntervalInMin?: number; +} + +export interface PrometheusExporterResponse { + result: string; +} + +export class PrometheusExporter { + public readonly metricsPollingIntervalInMin: number; + public readonly transactions: Transactions = []; + + constructor( + public readonly prometheusExporterOptions: PrometheusExporterOptions, + ) { + this.metricsPollingIntervalInMin = + prometheusExporterOptions.pollingIntervalInMin || 1; + } + + public addCurrentTransaction(startTimestamp: Date, endTimestamp: Date) { + this.transactions.push({ + startTime: startTimestamp, + endTime: endTimestamp, + } as Transaction); + } + + public async getPrometheusMetrics(): Promise< + PrometheusExporterMetricsResponse + > { + const result = { + result: await promClient.register.getSingleMetricAsString("totalTxCount"), + }; + return result; + } + + public startMetricsCollection(): NodeJS.Timeout { + promClient.collectDefaultMetrics(); + + const pollTimeoutRefreshIntervalId = setInterval(() => { + collectMetrics(this.transactions); + }, this.metricsPollingIntervalInMin * 60 * 1000); + collectMetrics(this.transactions); + + return pollTimeoutRefreshIntervalId; + } +} diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/response.type.ts b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/response.type.ts new file mode 100644 index 0000000000..f01e8a4c55 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-fabric/src/main/typescript/prometheus-exporter/response.type.ts @@ -0,0 +1,6 @@ +export type Transaction = { + startTime: Date; + endTime: Date; +}; + +export type Transactions = Transaction[]; diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v1-4-x/run-transaction-endpoint-v1.test.ts b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v1-4-x/run-transaction-endpoint-v1.test.ts index 477ae72415..ff46abdba3 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v1-4-x/run-transaction-endpoint-v1.test.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v1-4-x/run-transaction-endpoint-v1.test.ts @@ -100,6 +100,7 @@ test("runs tx on a Fabric v1.4.8 ledger", async (t: Test) => { }, }; const plugin = new PluginLedgerConnectorFabric(pluginOptions); + const pollTimeoutRefreshIntervalId = plugin.startPrometheusExporterMetricsCollection(); const expressApp = express(); expressApp.use(bodyParser.json({ limit: "250mb" })); @@ -173,6 +174,23 @@ test("runs tx on a Fabric v1.4.8 ledger", async (t: Test) => { t.ok(car277.Record.owner, `Car object has "Record"."owner" property OK`); t.equal(car277.Record.owner, carOwner, `Car has expected owner OK`); } - + await new Promise((resolve) => setTimeout(resolve, 200000)); + { + const promExporter = plugin.getPrometheusExporter(); + const res = await apiClient.getPrometheusExporterMetricsV1({ + promExporter: promExporter, + }); + const promMetricsOutput = + '# HELP totalTxCount Total transactions executed\n# TYPE totalTxCount gauge\ntotalTxCount{type="totalTxCount"} 3'; + t.ok(res); + t.ok(res.data); + t.equal(res.status, 200); + t.equal( + res.data.result, + promMetricsOutput, + "Total Transaction Count of 3 recorded as expected. RESULT OK", + ); + } + clearInterval(pollTimeoutRefreshIntervalId); t.end(); }); diff --git a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts index 5952ea6ccf..c4fbe98e5d 100644 --- a/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts +++ b/packages/cactus-plugin-ledger-connector-fabric/src/test/typescript/integration/fabric-v2-2-x/run-transaction-endpoint-v1.test.ts @@ -100,6 +100,7 @@ test("runs tx on a Fabric v2.2.0 ledger", async (t: Test) => { }, }; const plugin = new PluginLedgerConnectorFabric(pluginOptions); + const pollTimeoutRefreshIntervalId = plugin.startPrometheusExporterMetricsCollection(); const expressApp = express(); expressApp.use(bodyParser.json({ limit: "250mb" })); @@ -174,5 +175,23 @@ test("runs tx on a Fabric v2.2.0 ledger", async (t: Test) => { t.equal(car277.Record.owner, carOwner, `Car has expected owner OK`); } + await new Promise((resolve) => setTimeout(resolve, 200000)); + { + const promExporter = plugin.getPrometheusExporter(); + const res = await apiClient.getPrometheusExporterMetricsV1({ + promExporter: promExporter, + }); + const promMetricsOutput = + '# HELP totalTxCount Total transactions executed\n# TYPE totalTxCount gauge\ntotalTxCount{type="totalTxCount"} 3'; + t.ok(res); + t.ok(res.data); + t.equal(res.status, 200); + t.equal( + res.data.result, + promMetricsOutput, + "Total Transaction Count of 3 recorded as expected. RESULT OK", + ); + } + clearInterval(pollTimeoutRefreshIntervalId); t.end(); });