import {MetricsManager} from 'pandora-component-metrics'; import { BaseGauge, BaseCounter, BaseHistogram, BaseMeter, BaseTimer, MetricType, BaseFastCompass, MetricName } from 'metrics-common'; import {EventEmitter} from 'events'; import {CompactMetricsCollector} from 'pandora-metrics-util'; const debug = require('debug')('pandora:reporter-manager:MetricsOscillator'); export interface MetricsOscillatorOption { interval: number; // ms } export class MetricsOscillator extends EventEmitter { options; interval: number; intervalHandler = null; metricsManager: MetricsManager; constructor(metricsManager: MetricsManager, options: MetricsOscillatorOption) { super(); this.options = options; this.interval = options.interval; this.metricsManager = metricsManager; } start() { const {interval} = this; if(!this.intervalHandler) { this.intervalHandler = setInterval(async () => { this.collect().catch((err) => { debug('collect error', err); }); }, interval); // non blocking this.intervalHandler.unref(); } } async collect() { debug('exec report once'); const categoryMetrics = this.metricsManager.getAllCategoryMetrics(); await this.report( { gauges: >> categoryMetrics.get(MetricType.GAUGE), counters: > categoryMetrics.get(MetricType.COUNTER), histograms: > categoryMetrics.get(MetricType.HISTOGRAM), meters: > categoryMetrics.get(MetricType.METER), timers: > categoryMetrics.get(MetricType.TIMER), fastCompasses: > categoryMetrics.get(MetricType.FASTCOMPASS) } ); } async report(metricsData: { gauges: Map>, counters: Map, histograms: Map, meters: Map, timers: Map, fastCompasses: Map }) { const {gauges, counters, histograms, meters, timers, fastCompasses} = metricsData; const timestamp = Date.now(); const collector = new CompactMetricsCollector({ reportInterval: this.interval / 1000, }); const gaugesArr: BaseGauge[] = Array.from(gauges.values()); const results: number[] = await Promise.all(gaugesArr.map((gauge) => { return gauge.getValue(); })); Array.from(gauges.keys()).forEach((key: string, index) => { collector.collectGauge(MetricName.parseKey(key), results[index], timestamp); }); for (const [key, counter] of counters.entries()) { collector.collectCounter(MetricName.parseKey(key), counter, timestamp); } for (const [key, histogram] of histograms.entries()) { collector.collectHistogram(MetricName.parseKey(key), histogram, timestamp); } for (const [key, meter] of meters.entries()) { collector.collectMeter(MetricName.parseKey(key), meter, timestamp); } for (const [key, timer] of timers.entries()) { collector.collectTimer(MetricName.parseKey(key), timer, timestamp); } for (const [key, fastCompass] of fastCompasses.entries()) { collector.collectFastCompass(MetricName.parseKey(key), fastCompass, timestamp); } try { const list = []; for (const metricObject of collector.build()) { /* istanbul ignore else */ if (metricObject && metricObject.toJSON) { list.push(metricObject.toJSON()); } } if(list.length) { this.emit('oscillate', list); } } catch (err) { debug('report metrics data error!', err); } } stop() { this.intervalHandler && clearInterval(this.intervalHandler); this.intervalHandler = null; } }