From 44b7c446df93993e2fb7f2ffdf7dfc8a6d8edc0c Mon Sep 17 00:00:00 2001 From: Ashna Date: Sun, 4 Aug 2024 14:16:00 +0000 Subject: [PATCH] =?UTF-8?q?feat(iroha-connector):=20add=20prometheus=20exp?= =?UTF-8?q?orter=20to=20the=20plugin=20=C2=A0=20Primary=20Changes=20------?= =?UTF-8?q?----------=201.=20Added=20Prometheus=20Exporter=20to=20Iroha=20?= =?UTF-8?q?ledger=20plugin=202.=20Added=20Prometheus=20Metrics=20tracker?= =?UTF-8?q?=20to=20relevant=20iroha=20tests.=20=C2=A0=20Fixes=20#1260?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ashnashahgrover --- .../v21-deploy-contract-from-json.test.ts | 2 +- .../package.json | 1 + .../src/main/json/openapi.json | 29 +++++ .../src/main/json/openapi.tpl.json | 29 +++++ .../cactus-iroha-sdk-wrapper/client.ts | 16 +++ .../generated/openapi/typescript-axios/api.ts | 60 +++++++++++ .../plugin-ledger-connector-iroha2.ts | 45 +++++++- .../prometheus-exporter/data-fetcher.ts | 10 ++ .../typescript/prometheus-exporter/metrics.ts | 10 ++ .../prometheus-exporter.ts | 39 +++++++ .../prometheus-exporter/response.type.ts | 3 + ...prometheus-exporter-metrics-endpoint-v1.ts | 102 ++++++++++++++++++ ...nerate-and-send-signed-transaction.test.ts | 24 +++++ .../iroha2-setup-and-basic-operations.test.ts | 24 +++++ yarn.lock | 1 + 15 files changed, 392 insertions(+), 3 deletions(-) create mode 100644 packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/data-fetcher.ts create mode 100644 packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/metrics.ts create mode 100644 packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/prometheus-exporter.ts create mode 100644 packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/response.type.ts create mode 100644 packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/web-services/get-prometheus-exporter-metrics-endpoint-v1.ts diff --git a/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/v21-deploy-contract-from-json.test.ts b/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/v21-deploy-contract-from-json.test.ts index 553c9630168..3fba1175cb4 100644 --- a/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/v21-deploy-contract-from-json.test.ts +++ b/packages/cactus-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-ledger-connector-besu/deploy-contract/v21-deploy-contract-from-json.test.ts @@ -480,4 +480,4 @@ describe("PluginLedgerConnectorBesu", () => { expect(res.status).toEqual(200); expect(res.data.includes(promMetricsOutput)).toBeTrue(); }); -}); +}); \ No newline at end of file diff --git a/packages/cactus-plugin-ledger-connector-iroha2/package.json b/packages/cactus-plugin-ledger-connector-iroha2/package.json index 31e71536032..cc3f3c4560c 100644 --- a/packages/cactus-plugin-ledger-connector-iroha2/package.json +++ b/packages/cactus-plugin-ledger-connector-iroha2/package.json @@ -58,6 +58,7 @@ "express": "4.19.2", "fast-safe-stringify": "2.1.1", "hada": "0.0.8", + "prom-client": "15.1.3", "rxjs": "7.8.1", "sanitize-html": "2.12.1", "socket.io": "4.6.2", diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/json/openapi.json b/packages/cactus-plugin-ledger-connector-iroha2/src/main/json/openapi.json index a5903bc7b42..1418b58f29d 100644 --- a/packages/cactus-plugin-ledger-connector-iroha2/src/main/json/openapi.json +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/json/openapi.json @@ -488,6 +488,10 @@ } } }, + "PrometheusExporterMetricsResponse": { + "type": "string", + "nullable": false + }, "GenerateTransactionRequestV1": { "type": "object", "description": "Request for generating transaction or query payload that can be signed on the client side.", @@ -623,6 +627,31 @@ } } }, + "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha2/get-prometheus-exporter-metrics": { + "get": { + "x-hyperledger-cacti": { + "http": { + "verbLowerCase": "get", + "path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha2/get-prometheus-exporter-metrics" + } + }, + "operationId": "getPrometheusMetricsV1", + "summary": "Get the Prometheus Metrics", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PrometheusExporterMetricsResponse" + } + } + } + } + } + } + }, "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha2/query": { "post": { "x-hyperledger-cacti": { diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/json/openapi.tpl.json b/packages/cactus-plugin-ledger-connector-iroha2/src/main/json/openapi.tpl.json index a5903bc7b42..1418b58f29d 100644 --- a/packages/cactus-plugin-ledger-connector-iroha2/src/main/json/openapi.tpl.json +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/json/openapi.tpl.json @@ -488,6 +488,10 @@ } } }, + "PrometheusExporterMetricsResponse": { + "type": "string", + "nullable": false + }, "GenerateTransactionRequestV1": { "type": "object", "description": "Request for generating transaction or query payload that can be signed on the client side.", @@ -623,6 +627,31 @@ } } }, + "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha2/get-prometheus-exporter-metrics": { + "get": { + "x-hyperledger-cacti": { + "http": { + "verbLowerCase": "get", + "path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha2/get-prometheus-exporter-metrics" + } + }, + "operationId": "getPrometheusMetricsV1", + "summary": "Get the Prometheus Metrics", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PrometheusExporterMetricsResponse" + } + } + } + } + } + } + }, "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha2/query": { "post": { "x-hyperledger-cacti": { diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/cactus-iroha-sdk-wrapper/client.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/cactus-iroha-sdk-wrapper/client.ts index ac2855441af..a1c6bb0d9f3 100644 --- a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/cactus-iroha-sdk-wrapper/client.ts +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/cactus-iroha-sdk-wrapper/client.ts @@ -76,6 +76,7 @@ import { Iroha2BaseConfigTorii, } from "../generated/openapi/typescript-axios"; import { IrohaV2PrerequisitesProvider } from "./prerequisites-provider"; +import { PrometheusExporter } from "../prometheus-exporter/prometheus-exporter"; setCrypto(crypto); @@ -792,6 +793,7 @@ export class CactusIrohaV2Client { * @returns `TransactResponseV1` */ public async send( + prometheusExporter: PrometheusExporter, txParams?: TransactionPayloadParameters, waitForCommit = false, ): Promise { @@ -820,6 +822,9 @@ export class CactusIrohaV2Client { this.prerequisitesProvider.getApiHttpProperties(), signedTx, ); + //counter will increase here + prometheusExporter.addCurrentTransaction() + this.clear(); if (statusPromise) { @@ -843,6 +848,7 @@ export class CactusIrohaV2Client { public async sendSignedPayload( signedPayload: VersionedSignedTransaction | ArrayBufferView, waitForCommit = false, + prometheusExporter: PrometheusExporter, ): Promise { Checks.truthy(signedPayload, "sendSigned arg signedPayload"); @@ -853,16 +859,26 @@ export class CactusIrohaV2Client { const hash = computeTransactionHash(signedPayload.as("V1").payload); if (waitForCommit) { const statusPromise = this.waitForTransactionStatus(hash); + await Torii.submit( this.prerequisitesProvider.getApiHttpProperties(), signedPayload, ); + + //counter will increase here + prometheusExporter.addCurrentTransaction() + return await statusPromise; } else { + await Torii.submit( this.prerequisitesProvider.getApiHttpProperties(), signedPayload, ); + + //counter will increase here + prometheusExporter.addCurrentTransaction() + return { hash: bytesToHex([...hash]), status: TransactionStatusV1.Submitted, diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/generated/openapi/typescript-axios/api.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/generated/openapi/typescript-axios/api.ts index 85d89d4103b..1c10d9eb1cb 100644 --- a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/generated/openapi/typescript-axios/api.ts +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/generated/openapi/typescript-axios/api.ts @@ -659,6 +659,36 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati options: localVarRequestOptions, }; }, + /** + * + * @summary Get the Prometheus Metrics + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getPrometheusMetricsV1: async (options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha2/get-prometheus-exporter-metrics`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @summary Executes a query on a Iroha V2 ledger and returns it\'s results. @@ -748,6 +778,16 @@ export const DefaultApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.generateTransactionV1(generateTransactionRequestV1, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary Get the Prometheus Metrics + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getPrometheusMetricsV1(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getPrometheusMetricsV1(options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary Executes a query on a Iroha V2 ledger and returns it\'s results. @@ -790,6 +830,15 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa generateTransactionV1(generateTransactionRequestV1?: GenerateTransactionRequestV1, options?: any): AxiosPromise { return localVarFp.generateTransactionV1(generateTransactionRequestV1, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Get the Prometheus Metrics + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getPrometheusMetricsV1(options?: any): AxiosPromise { + return localVarFp.getPrometheusMetricsV1(options).then((request) => request(axios, basePath)); + }, /** * * @summary Executes a query on a Iroha V2 ledger and returns it\'s results. @@ -832,6 +881,17 @@ export class DefaultApi extends BaseAPI { return DefaultApiFp(this.configuration).generateTransactionV1(generateTransactionRequestV1, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Get the Prometheus Metrics + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApi + */ + public getPrometheusMetricsV1(options?: AxiosRequestConfig) { + return DefaultApiFp(this.configuration).getPrometheusMetricsV1(options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Executes a query on a Iroha V2 ledger and returns it\'s results. diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/plugin-ledger-connector-iroha2.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/plugin-ledger-connector-iroha2.ts index 48ad6e142d7..9f6b6134646 100644 --- a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/plugin-ledger-connector-iroha2.ts +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/plugin-ledger-connector-iroha2.ts @@ -64,6 +64,13 @@ import { CactusIrohaV2QueryClient } from "./cactus-iroha-sdk-wrapper/query"; import { LengthOf, stringifyBigIntReplacer } from "./utils"; import { createAccountId } from "./cactus-iroha-sdk-wrapper/data-factories"; +import { + GetPrometheusExporterMetricsEndpointV1, + IGetPrometheusExporterMetricsEndpointV1Options, +} from "./web-services/get-prometheus-exporter-metrics-endpoint-v1"; +import { PrometheusExporter } from "./prometheus-exporter/prometheus-exporter"; + + /** * Input options for PluginLedgerConnectorIroha2. */ @@ -72,6 +79,7 @@ export interface IPluginLedgerConnectorIroha2Options pluginRegistry: PluginRegistry; logLevel?: LogLevelDesc; defaultConfig?: Iroha2BaseConfig; + prometheusExporter?: PrometheusExporter; } /** @@ -84,6 +92,7 @@ export class PluginLedgerConnectorIroha2 IPluginWebService { private readonly instanceId: string; + public prometheusExporter: PrometheusExporter; private readonly log: Logger; private readonly defaultConfig: Iroha2BaseConfig | undefined; private endpoints: IWebServiceEndpoint[] | undefined; @@ -102,6 +111,17 @@ export class PluginLedgerConnectorIroha2 this.instanceId = options.instanceId; + this.prometheusExporter = + options.prometheusExporter || + new PrometheusExporter({ pollingIntervalInMin: 1 }); + Checks.truthy( + this.prometheusExporter, + `${fnTag} options.prometheusExporter`, + ); + + this.prometheusExporter.startMetricsCollection(); + + this.defaultConfig = options.defaultConfig; // Remove proto in case we use merge method vulnerable to proto pollution if (this.defaultConfig instanceof Object) { @@ -133,6 +153,16 @@ export class PluginLedgerConnectorIroha2 return OAS; } + public getPrometheusExporter(): PrometheusExporter { + return this.prometheusExporter; + } + + public async getPrometheusExporterMetrics(): Promise { + const res: string = await this.prometheusExporter.getPrometheusMetrics(); + this.log.debug(`getPrometheusExporterMetrics() response: %o`, res); + return res; + } + /** * @warning Method not implemented - do not use! */ @@ -266,6 +296,15 @@ export class PluginLedgerConnectorIroha2 }), ]; + { + const opts: IGetPrometheusExporterMetricsEndpointV1Options = { + connector: this, + logLevel: this.options.logLevel, + }; + const endpoint = new GetPrometheusExporterMetricsEndpointV1(opts); + endpoints.push(endpoint); + } + this.endpoints = endpoints; return endpoints; } @@ -589,7 +628,6 @@ export class PluginLedgerConnectorIroha2 if (!reqParams) { return undefined; } - return { ttl: reqParams.ttl ? BigInt(reqParams.ttl) : undefined, creationTime: reqParams.creationTime @@ -610,11 +648,13 @@ export class PluginLedgerConnectorIroha2 public async transact(req: TransactRequestV1): Promise { const fnTag = `${this.className}:transact()`; const client = await this.createClient(req.baseConfig); - + // + try { if (req.transaction) { this.processInstructionsRequests(client, req.transaction.instruction); return await client.send( + this.prometheusExporter, this.tryParseTransactionParams(req.transaction.params), req.waitForCommit, ); @@ -625,6 +665,7 @@ export class PluginLedgerConnectorIroha2 return await client.sendSignedPayload( transactionBinary, req.waitForCommit, + this.prometheusExporter ); } else { const eMsg = diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/data-fetcher.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/data-fetcher.ts new file mode 100644 index 00000000000..da7c8e672f3 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/data-fetcher.ts @@ -0,0 +1,10 @@ +import { Transactions } from "./response.type"; + +import { totalTxCount, K_CACTUS_IROHA2_TOTAL_TX_COUNT } from "./metrics"; + +export async function collectMetrics( + transactions: Transactions, +): Promise { + transactions.counter++; + totalTxCount.labels(K_CACTUS_IROHA2_TOTAL_TX_COUNT).set(transactions.counter); +} diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/metrics.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/metrics.ts new file mode 100644 index 00000000000..3800f875e3b --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/metrics.ts @@ -0,0 +1,10 @@ +import { Gauge } from "prom-client"; + +export const K_CACTUS_IROHA2_TOTAL_TX_COUNT = "cactus_iroha2_total_tx_count"; + +export const totalTxCount = new Gauge({ + registers: [], + name: "cactus_iroha2_total_tx_count", + help: "Total transactions executed", + labelNames: ["type"], +}); diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/prometheus-exporter.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/prometheus-exporter.ts new file mode 100644 index 00000000000..0df23ce3abf --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/prometheus-exporter.ts @@ -0,0 +1,39 @@ +import promClient, { Registry } from "prom-client"; +import { Transactions } from "./response.type"; +import { collectMetrics } from "./data-fetcher"; +import { K_CACTUS_IROHA2_TOTAL_TX_COUNT } from "./metrics"; +import { totalTxCount } from "./metrics"; + +export interface IPrometheusExporterOptions { + pollingIntervalInMin?: number; +} + +export class PrometheusExporter { + public readonly metricsPollingIntervalInMin: number; + public readonly transactions: Transactions = { counter: 0 }; + public readonly registry: Registry; + + constructor( + public readonly prometheusExporterOptions: IPrometheusExporterOptions, + ) { + this.metricsPollingIntervalInMin = + prometheusExporterOptions.pollingIntervalInMin || 1; + this.registry = new Registry(); + } + + public addCurrentTransaction(): void { + collectMetrics(this.transactions); + } + + public async getPrometheusMetrics(): Promise { + const result = await this.registry.getSingleMetricAsString( + K_CACTUS_IROHA2_TOTAL_TX_COUNT, + ); + return result; + } + + public startMetricsCollection(): void { + this.registry.registerMetric(totalTxCount); + promClient.collectDefaultMetrics({ register: this.registry }); + } +} diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/response.type.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/response.type.ts new file mode 100644 index 00000000000..3f1bc7f4911 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/prometheus-exporter/response.type.ts @@ -0,0 +1,3 @@ +export type Transactions = { + counter: number; +}; diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/web-services/get-prometheus-exporter-metrics-endpoint-v1.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/web-services/get-prometheus-exporter-metrics-endpoint-v1.ts new file mode 100644 index 00000000000..4898a892b54 --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/main/typescript/web-services/get-prometheus-exporter-metrics-endpoint-v1.ts @@ -0,0 +1,102 @@ +import { Express, Request, Response } from "express"; + +import { registerWebServiceEndpoint } from "@hyperledger/cactus-core"; + +import OAS from "../../json/openapi.json"; + +import { + IWebServiceEndpoint, + IExpressRequestHandler, + IEndpointAuthzOptions, +} from "@hyperledger/cactus-core-api"; + +import { + LogLevelDesc, + Logger, + LoggerProvider, + Checks, + IAsyncProvider, +} from "@hyperledger/cactus-common"; + +import { PluginLedgerConnectorIroha2 } from "../plugin-ledger-connector-iroha2"; + +export interface IGetPrometheusExporterMetricsEndpointV1Options { + connector: PluginLedgerConnectorIroha2; + logLevel?: LogLevelDesc; +} + +export class GetPrometheusExporterMetricsEndpointV1 + implements IWebServiceEndpoint +{ + private readonly log: Logger; + + constructor( + public readonly options: IGetPrometheusExporterMetricsEndpointV1Options, + ) { + const fnTag = "GetPrometheusExporterMetricsEndpointV1#constructor()"; + + Checks.truthy(options, `${fnTag} options`); + Checks.truthy(options.connector, `${fnTag} options.connector`); + + const label = "get-prometheus-exporter-metrics-endpoint"; + const level = options.logLevel || "INFO"; + this.log = LoggerProvider.getOrCreate({ label, level }); + } + + getAuthorizationOptionsProvider(): IAsyncProvider { + // TODO: make this an injectable dependency in the constructor + return { + get: async () => ({ + isProtected: true, + requiredRoles: [], + }), + }; + } + + public getExpressRequestHandler(): IExpressRequestHandler { + return this.handleRequest.bind(this); + } + + public get oasPath(): (typeof OAS.paths)["/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha2/get-prometheus-exporter-metrics"] { + return OAS.paths[ + "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-iroha2/get-prometheus-exporter-metrics" + ]; + } + + public getPath(): string { + return this.oasPath.get["x-hyperledger-cacti"].http.path; + } + + public getVerbLowerCase(): string { + return this.oasPath.get["x-hyperledger-cacti"].http.verbLowerCase; + } + + public getOperationId(): string { + return this.oasPath.get.operationId; + } + + public async registerExpress( + expressApp: Express, + ): Promise { + await registerWebServiceEndpoint(expressApp, this); + return this; + } + + async handleRequest(req: Request, res: Response): Promise { + const fnTag = "GetPrometheusExporterMetrics#handleRequest()"; + const verbUpper = this.getVerbLowerCase().toUpperCase(); + this.log.debug(`${verbUpper} ${this.getPath()}`); + + try { + const resBody = + await this.options.connector.getPrometheusExporterMetrics(); + res.status(200); + res.send(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-iroha2/src/test/typescript/integration/iroha2-generate-and-send-signed-transaction.test.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/test/typescript/integration/iroha2-generate-and-send-signed-transaction.test.ts index 07ac3e53ed9..196e7e2f0a9 100644 --- a/packages/cactus-plugin-ledger-connector-iroha2/src/test/typescript/integration/iroha2-generate-and-send-signed-transaction.test.ts +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/test/typescript/integration/iroha2-generate-and-send-signed-transaction.test.ts @@ -31,6 +31,7 @@ import { addRandomSuffix } from "../test-helpers/utils"; import "jest-extended"; import { TransactionPayload } from "@iroha2/data-model"; import { signIrohaV2Query } from "../../../main/typescript/iroha-sign-utils"; +import { K_CACTUS_IROHA2_TOTAL_TX_COUNT } from "../../../main/typescript/prometheus-exporter/metrics"; // Logger setup const log: Logger = LoggerProvider.getOrCreate({ @@ -613,4 +614,27 @@ describe("Generate and send signed transaction tests", () => { log.info("Bob (source) balance after final transfer:", finalBobBalance); expect(finalBobBalance).toEqual(transferValue - transferBackValue); }); + + test("get prometheus exporter metrics", async () => { + + const res = await env.apiClient.getPrometheusMetricsV1(); + const promMetricsOutput = + "# HELP " + + K_CACTUS_IROHA2_TOTAL_TX_COUNT + + " Total transactions executed\n" + + "# TYPE " + + K_CACTUS_IROHA2_TOTAL_TX_COUNT + + " gauge\n" + + K_CACTUS_IROHA2_TOTAL_TX_COUNT + + '{type="' + + K_CACTUS_IROHA2_TOTAL_TX_COUNT + + '"} 8'; + + + expect(res).toBeTruthy(); + expect(res.data).toBeTruthy(); + expect(res.status).toEqual(200); + expect(res.data.includes(promMetricsOutput)).toBeTrue(); + }); + }); diff --git a/packages/cactus-plugin-ledger-connector-iroha2/src/test/typescript/integration/iroha2-setup-and-basic-operations.test.ts b/packages/cactus-plugin-ledger-connector-iroha2/src/test/typescript/integration/iroha2-setup-and-basic-operations.test.ts index f966817b011..fb9b7d378a3 100644 --- a/packages/cactus-plugin-ledger-connector-iroha2/src/test/typescript/integration/iroha2-setup-and-basic-operations.test.ts +++ b/packages/cactus-plugin-ledger-connector-iroha2/src/test/typescript/integration/iroha2-setup-and-basic-operations.test.ts @@ -34,6 +34,7 @@ import { generateTestIrohaCredentials, } from "../test-helpers/iroha2-env-setup"; import { addRandomSuffix } from "../test-helpers/utils"; +import { K_CACTUS_IROHA2_TOTAL_TX_COUNT } from "../../../main/typescript/prometheus-exporter/metrics"; setCrypto(crypto); @@ -393,4 +394,27 @@ describe("Setup and basic endpoint tests", () => { }), ).toReject(); }); + + test("get prometheus exporter metrics", async () => { + + const res = await env.apiClient.getPrometheusMetricsV1(); + const promMetricsOutput = + "# HELP " + + K_CACTUS_IROHA2_TOTAL_TX_COUNT + + " Total transactions executed\n" + + "# TYPE " + + K_CACTUS_IROHA2_TOTAL_TX_COUNT + + " gauge\n" + + K_CACTUS_IROHA2_TOTAL_TX_COUNT + + '{type="' + + K_CACTUS_IROHA2_TOTAL_TX_COUNT + + '"} 6'; + + + expect(res).toBeTruthy(); + expect(res.data).toBeTruthy(); + expect(res.status).toEqual(200); + expect(res.data.includes(promMetricsOutput)).toBeTrue(); + }); + }); diff --git a/yarn.lock b/yarn.lock index caa2bee0f5f..0e8ec446001 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10458,6 +10458,7 @@ __metadata: hada: "npm:0.0.8" jest: "npm:29.6.2" jest-extended: "npm:4.0.1" + prom-client: "npm:15.1.3" rxjs: "npm:7.8.1" sanitize-html: "npm:2.12.1" socket.io: "npm:4.6.2"