UNPKG

@zombienet/orchestrator

Version:

ZombieNet aim to be a testing framework for substrate based blockchains, providing a simple cli tool that allow users to spawn and test ephemeral Substrate based networks

167 lines (166 loc) 7.27 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.fetchMetrics = fetchMetrics; exports.getHistogramBuckets = getHistogramBuckets; exports.getMetricName = getMetricName; exports.getProcessStartTimeKey = getProcessStartTimeKey; const debug = require("debug")("zombie::metrics"); const utils_1 = require("@zombienet/utils"); const constants_1 = require("../constants"); const parseLine_1 = require("./parseLine"); // Map well know metric keys used to regex var metricKeysMapping; (function (metricKeysMapping) { metricKeysMapping["BlockHeight"] = "block_height{status=\"best\"}"; metricKeysMapping["FinalizedHeight"] = "block_height{status=\"finalized\"}"; metricKeysMapping["PeersCount"] = "sub_libp2p_peers_count"; })(metricKeysMapping || (metricKeysMapping = {})); function fetchMetrics(metricUri_1) { return __awaiter(this, arguments, void 0, function* (metricUri, node_name = "") { let metrics = {}; // empty by default const debug_msg = node_name ? `[${node_name}]` : ""; try { debug([debug_msg, `fetching: ${metricUri}`].join(" ")); const fetchResult = yield fetch(metricUri, { signal: (0, utils_1.TimeoutAbortController)(2).signal, method: "GET", headers: { accept: "application/json", }, }); if (!fetchResult.ok) { debug([debug_msg, `fetch error - status: ${fetchResult.status}`].join(" ")); throw new Error(`Error - status: ${fetchResult.status}`); } const response = yield fetchResult.text(); metrics = _extractMetrics(response); } catch (err) { debug(`ERR: ${err}`); console.log(`\n${utils_1.decorators.red(`Error`)} \t ${utils_1.decorators.bright(`fetching metrics from: ${metricUri} ${debug_msg}`)}`); } return metrics; }); } function getHistogramBuckets(metricUri, metricName) { return __awaiter(this, void 0, void 0, function* () { debug(`fetching: ${metricUri}`); const fetchResult = yield fetch(metricUri, { signal: (0, utils_1.TimeoutAbortController)(2).signal, method: "GET", headers: { accept: "application/json", }, }); if (!fetchResult.ok) { throw new Error(`Error - status: ${fetchResult.status}`); } const response = yield fetchResult.text(); let previousBucketValue = 0; const buckets = {}; const resolvedMetricName = metricName.includes("_bucket") ? metricName : `${metricName}_bucket`; const parsedMetricInput = (0, parseLine_1.parseLine)(resolvedMetricName); for (const line of response.split("\n")) { if (line.length === 0 || line[0] === "#") continue; // comments and empty lines const parsedLine = (0, parseLine_1.parseLine)(line); if (parsedMetricInput.name === parsedLine.name) { // check labels if are presents let thereAreSomeMissingLabel = false; for (const [k, v] of parsedMetricInput.labels.entries()) { console.log(`looking for key ${k}`); if (!parsedLine.labels.has(k) || parsedLine.labels.get(k) !== v) { thereAreSomeMissingLabel = true; break; } } if (thereAreSomeMissingLabel) continue; // don't match const metricValue = parseInt(parsedLine.value); const leLabel = parsedLine.labels.get("le"); buckets[leLabel] = metricValue - previousBucketValue; previousBucketValue = metricValue; debug(`${parsedLine.name} le:${leLabel} ${metricValue}`); } } return buckets; }); } function getMetricName(metricName) { let metricNameTouse = metricName; switch (metricName) { case "blockheight": case "block height": case "best block": metricNameTouse = metricKeysMapping.BlockHeight; break; case "finalised height": case "finalised block": metricNameTouse = metricKeysMapping.FinalizedHeight; break; case "peers count": case "peers": metricNameTouse = metricKeysMapping.PeersCount; break; default: break; } return metricNameTouse; } function getProcessStartTimeKey(prefix = constants_1.DEFAULT_PROMETHEUS_PREFIX) { return `${prefix}_process_start_time_seconds`; } function _extractMetrics(text) { const rawMetrics = {}; rawMetrics["_raw"] = {}; for (const line of text.split("\n")) { if (line.length === 0 || line[0] === "#") continue; // comments and empty lines const parsedLine = (0, parseLine_1.parseLine)(line); const metricValue = parseInt(parsedLine.value); // get the namespace of the key const parts = parsedLine.name.split("_"); const ns = parts[0]; const rawMetricNameWithOutNs = parts.slice(1).join("_"); const labelStrings = []; const labelStringsWithOutChain = []; for (const [k, v] of parsedLine.labels.entries()) { labelStrings.push(`${k}="${v}"`); if (k !== "chain") labelStringsWithOutChain.push(`${k}="${v}"`); } if (!rawMetrics[ns]) rawMetrics[ns] = {}; // store the metric with and without the chain if (labelStrings.length > 0) { rawMetrics[ns][`${rawMetricNameWithOutNs}{${labelStrings.join(",")}}`] = metricValue; rawMetrics["_raw"][`${parsedLine.name}{${labelStrings.join(",")}}`] = metricValue; } else { rawMetrics[ns][rawMetricNameWithOutNs] = metricValue; rawMetrics["_raw"][parsedLine.name] = metricValue; } if (labelStringsWithOutChain.length > 0) { rawMetrics[ns][`${rawMetricNameWithOutNs}{${labelStringsWithOutChain.join(",")}}`] = metricValue; rawMetrics["_raw"][`${parsedLine.name}{${labelStringsWithOutChain.join(",")}}`] = metricValue; } else { rawMetrics[ns][rawMetricNameWithOutNs] = metricValue; rawMetrics["_raw"][parsedLine.name] = metricValue; } } return rawMetrics; }