UNPKG

moleculer

Version:

Fast & powerful microservices framework for Node.JS

236 lines (205 loc) 5.38 kB
/* * moleculer * Copyright (c) 2023 MoleculerJS (https://github.com/moleculerjs/moleculer) * MIT Licensed */ "use strict"; const BaseReporter = require("./base"); const _ = require("lodash"); const kleur = require("kleur"); const METRIC = require("../constants"); const { isFunction } = require("../../utils"); /** * Import types * * @typedef {import("../registry")} MetricRegistry * @typedef {import("./console").ConsoleReporterOptions} ConsoleReporterOptions * @typedef {import("./console")} ConsoleReporterClass * @typedef {import("../types/base")} BaseMetric */ /** * Console reporter for Moleculer Metrics * * @class ConsoleReporter * @extends {BaseReporter} * @implements {ConsoleReporterClass} */ class ConsoleReporter extends BaseReporter { /** * Creates an instance of ConsoleReporter. * * @param {ConsoleReporterOptions?} opts * @memberof ConsoleReporter */ constructor(opts) { super(opts); /** @type {ConsoleReporterOptions} */ this.opts = _.defaultsDeep(this.opts, { interval: 5, logger: null, colors: true, onlyChanges: true }); if (!this.opts.colors) kleur.enabled = false; this.lastChanges = new Set(); } /** * Initialize reporter * * @param {MetricRegistry} registry * @memberof ConsoleReporter */ init(registry) { super.init(registry); if (this.opts.interval > 0) { this.timer = setInterval(() => this.print(), this.opts.interval * 1000); this.timer.unref(); } } /** * Convert labels to label string * * @param {Object} labels * @returns {String} * @memberof ConsoleReporter */ labelsToStr(labels) { const keys = Object.keys(labels); if (keys.length === 0) return kleur.gray("{}"); return ( kleur.gray("{") + keys .map( key => `${kleur.gray(this.formatLabelName(key))}: ${kleur.magenta( "" + labels[key] )}` ) .join(", ") + kleur.gray("}") ); } /** * Print metrics to the console. * * @memberof ConsoleReporter */ print() { let list = this.registry.list({ includes: this.opts.includes, excludes: this.opts.excludes }); if (this.opts.onlyChanges) list = list.filter(metric => this.lastChanges.has(metric.name)); if (list.length === 0) return; this.log( kleur.gray(`------------------- [ METRICS START (${list.length}) ] -------------------`) ); list.forEach(metric => { this.log( kleur.cyan().bold(this.formatMetricName(metric.name)) + " " + kleur.gray("(" + metric.type + ")") ); if (metric.values.size === 0) { this.log(kleur.gray(" <no values>")); } else { const unit = metric.unit ? kleur.gray(this.registry.pluralizeUnit(metric.unit)) : ""; metric.values.forEach(item => { let val; const labelStr = this.labelsToStr(item.labels); switch (metric.type) { case METRIC.TYPE_COUNTER: case METRIC.TYPE_GAUGE: case METRIC.TYPE_INFO: val = item.value === "" ? kleur.grey("<empty string>") : kleur.green().bold(item.value); if (item.rate != null) { /*const s = []; Object.keys(item.rates).forEach(b => { s.push(`Rate${b}: ${item.rates[b] != null ? item.rates[b].toFixed(2) : "-"}`); }); val = kleur.green().bold(`Value: ${val} | ` + s.join(" | ")); */ val = val + kleur.grey(" | Rate: ") + (item.rate != null ? kleur.green().bold(item.rate.toFixed(2)) : "-"); } break; case METRIC.TYPE_HISTOGRAM: { const s = []; s.push(`Count: ${item.count}`); if (item.buckets) { Object.keys(item.buckets).forEach(b => { s.push( `${b}: ${item.buckets[b] != null ? item.buckets[b] : "-"}` ); }); } if (item.quantiles) { s.push(`Min: ${item.min != null ? item.min.toFixed(2) : "-"}`); s.push(`Mean: ${item.mean != null ? item.mean.toFixed(2) : "-"}`); s.push( `Var: ${item.variance != null ? item.variance.toFixed(2) : "-"}` ); s.push( `StdDev: ${item.stdDev != null ? item.stdDev.toFixed(2) : "-"}` ); s.push(`Max: ${item.max != null ? item.max.toFixed(2) : "-"}`); Object.keys(item.quantiles).forEach(key => { s.push( `${key}: ${ item.quantiles[key] != null ? item.quantiles[key].toFixed(2) : "-" }` ); }); } if (item.rate != null) s.push(`Rate: ${item.rate != null ? item.rate.toFixed(2) : "-"}`); val = kleur.green().bold(s.join(" | ")); break; } } this.log(` ${labelStr}: ${val} ${unit}`); }); } this.log(""); }); this.log( kleur.gray(`-------------------- [ METRICS END (${list.length}) ] --------------------`) ); this.lastChanges.clear(); } /** * Print messages * * @param {...any} args */ log(...args) { if (isFunction(this.opts.logger)) { return this.opts.logger(...args); } else { return this.logger.info(...args); } } /** * Some metric has been changed. * * @param {BaseMetric} metric * * @memberof BaseReporter */ metricChanged(metric) { if (!this.matchMetricName(metric.name)) return; this.lastChanges.add(metric.name); } } module.exports = ConsoleReporter;