UNPKG

pandora-metrics

Version:
331 lines 13.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const MessengerUtil_1 = require("./util/MessengerUtil"); const MetricsConstants_1 = require("./MetricsConstants"); const index_1 = require("./common/index"); const AbstractIndicator_1 = require("./indicator/AbstractIndicator"); const util = require('util'); class MetricsServerManager extends AbstractIndicator_1.AbstractIndicator { constructor() { super(); this.messengerServer = new MessengerUtil_1.MetricsMessengerServer(MetricsConstants_1.MetricsConstants.METRICS_PANDORA_KEY); this.metricsClients = new Map(); this.allMetricsRegistry = this.getNewMetricRegistry(); this.metricRegistryMap = new Map(); this.metricsAndClientMap = new Map(); // store metrics in which client this.clientId = Math.random().toString(35).substr(2, 10); this.logger = console; this.enabled = true; this.group = 'metrics'; this.debug = require('debug')('pandora:metrics:server:' + this.clientId); this.debug(`start listen and wait client`); this.messengerServer.discovery(this.registerClient.bind(this)); } static getInstance() { if (!this.instance) { this.instance = new MetricsServerManager(); } return this.instance; } /** * 注册客户端 * @param data * @param reply * @param client */ registerClient(data, reply, client) { if (!this.enabled) { return; } // 这里统一维护一个客户端列表 client._APP_NAME = data.appName; client._CLIENT_ID = data.clientId; this.metricsClients.set(data.clientId, client); // 构建 report 通路 this.buildReportLink(client); // 清理客户端 this.bindRemove(client); this.debug(`Binding client(${data.clientId}), now client number = ${this.metricsClients.size}`); } buildReportLink(client) { // 处理接受的数据 client.on(this.getClientUplinkKey(client._APP_NAME, client._CLIENT_ID), (data) => { if (data.action === MetricsConstants_1.MetricsConstants.EVT_METRIC_CREATE) { this.registerMetric(data); } else if (data.action === MetricsConstants_1.MetricsConstants.EVT_METRIC_UPDATE) { this.updateMetric(data); } }); } bindRemove(client) { client.on('close', () => { let remove_id = client._CLIENT_ID; let remove_client = this.metricsClients.get(remove_id); remove_client && remove_client.close(); this.metricsClients.delete(remove_id); this.debug(`remove client(${remove_id})`); // remove metrics from registry let storeMetricsArr = this.metricsAndClientMap.get(remove_id); this.removeMetricInRegistry(this.allMetricsRegistry, storeMetricsArr); // remove in group map for (let registry of this.metricRegistryMap.values()) { this.removeMetricInRegistry(registry, storeMetricsArr); } // remove from metricsAndClientMap this.metricsAndClientMap.delete(remove_id); }); } removeMetricInRegistry(registry, storeMetricsArr) { for (let key of (storeMetricsArr || [])) { registry.remove(key); } } /** * 注册一个 metric * * @param data */ registerMetric(data) { // 创建新指标 let metric; let metricName = index_1.MetricName.parseKey(data.name); if (!this.metricsAndClientMap.has(data.clientId)) { this.metricsAndClientMap.set(data.clientId, []); } // set metrics to own store and can remove after disconnected let storeMetricsArr = this.metricsAndClientMap.get(data.clientId); storeMetricsArr.push(data.name); switch (data.type) { case 'GAUGE': metric = this.createGaugeProxy(metricName); break; case 'COUNTER': metric = this.allMetricsRegistry.counter(metricName); break; case 'METER': metric = this.allMetricsRegistry.meter(metricName); break; case 'TIMER': metric = this.allMetricsRegistry.timer(metricName); break; case 'HISTOGRAM': metric = this.allMetricsRegistry.histogram(metricName); break; default: metric = this.createGaugeProxy(metricName); } // 注册后加入分组 let metricRegistry = this.getMetricRegistryByGroup(data.group); metricRegistry.register(metricName, metric); // this.debug('---------------- current name registryMap ----------------'); // this.debug('current name registryMap = '); // this.debug(this.metricRegistryMap); // this.debug('current metricService allRegistryMap = '); // this.debug(this.allMetricsRegistry); // this.debug('-----------------------------------------------------------'); this.debug(`Register Metrics: name = ${data.name}, type = ${data.type}, group = ${data.group}, store number = ${this.allMetricsRegistry.getKeys().length}`); return metric; } updateMetric(data) { this.debug(`Invoke: name = ${data.name}, type = ${data.type}, method = ${data.method}, value = ${data.value}`); // 找指标 let metricName = index_1.MetricName.parseKey(data.name); let metric = this.allMetricsRegistry.getMetric(metricName); if (metric) { this.debug(`Invoke: find metric(${data.name}), type = ${metric.type}`); if (metric.type === data.type) { this.debug(`Invoke: type equal and call ${data.method}(${data.value})`); metric[data.method].apply(metric, data.value); } } else { this.debug(`Invoke: can't find msetric(${data.name})`); } } /** * 创建一个 Gauge 类型的代理实例 * @param metricName * @returns {any} */ createGaugeProxy(metricName) { let self = this; let metric = { async getValue() { self.debug('Invoke: invoke Gauge'); let results = await self.invoke({ metricKey: metricName.toString(), type: index_1.MetricType.GAUGE, }); self.debug(`Invoke: invoke Gauge and getValue = ${util.inspect(results)}`); return results; } }; self.allMetricsRegistry.register(metricName, metric); return metric; } /** * 对客户端的调用,现在用于 Gauge 类型的获取值 * @param args * @returns {Promise<void>} */ async invoke(args) { for (let client of this.getClients()) { let result = await new Promise((resolve) => { this.debug(`Invoke: eventKey(${this.getClientDownlinkKey(client._APP_NAME, client._CLIENT_ID)}), args = ${args}`); client.send(this.getClientDownlinkKey(client._APP_NAME, client._CLIENT_ID), args, (err, result) => { this.debug(`Invoke: invoke end and err = ${err}, results = ${result}`); resolve(result); }, MetricsConstants_1.MetricsConstants.CLIENT_TIME_OUT); }); if (result !== null && result !== undefined) { return result; } } } getClients() { return Array.from(this.metricsClients.values()); } getClient(clientId) { return this.metricsClients.get(clientId); } getMetric(name) { return this.allMetricsRegistry.getMetric(name); } getAllMetricsRegistry() { return this.allMetricsRegistry; } destroy() { this.enabled = false; for (let client of this.metricsClients.values()) { client.close(); } } register(group, name, metric) { if (!this.enabled) { return; } let newName; if (typeof name === 'string') { newName = index_1.MetricName.build(name); } else { newName = name; } // register to all first this.allMetricsRegistry.register(newName, metric); // register to name second const metricRegistry = this.getMetricRegistryByGroup(group); metricRegistry.register(newName, metric); } getMetricRegistryByGroup(group) { if (!this.metricRegistryMap.has(group)) { this.metricRegistryMap.set(group, this.getNewMetricRegistry()); } return this.metricRegistryMap.get(group); } hasMetricRegistryByGroup(group) { return this.metricRegistryMap.has(group); } getGauges(group, filter = index_1.MetricFilter.ALL) { let metricRegistry = this.getMetricRegistryByGroup(group); return metricRegistry.getGauges(filter); } getCounters(group, filter = index_1.MetricFilter.ALL) { let metricRegistry = this.getMetricRegistryByGroup(group); return metricRegistry.getCounters(filter); } getHistograms(group, filter = index_1.MetricFilter.ALL) { let metricRegistry = this.getMetricRegistryByGroup(group); return metricRegistry.getHistograms(filter); } getMeters(group, filter = index_1.MetricFilter.ALL) { let metricRegistry = this.getMetricRegistryByGroup(group); return metricRegistry.getMeters(filter); } getTimers(group, filter = index_1.MetricFilter.ALL) { let metricRegistry = this.getMetricRegistryByGroup(group); return metricRegistry.getTimers(filter); } getMetrics(group) { let metricRegistry = this.metricRegistryMap.get(group); if (metricRegistry) { return metricRegistry.getMetrics(); } return new Map(); } getCategoryMetrics(group, filter = index_1.MetricFilter.ALL) { const metricRegistry = this.metricRegistryMap.get(group); const result = new Map(); result.set(index_1.MetricType.GAUGE, metricRegistry.getGauges(filter)); result.set(index_1.MetricType.COUNTER, metricRegistry.getCounters(filter)); result.set(index_1.MetricType.HISTOGRAM, metricRegistry.getHistograms(filter)); result.set(index_1.MetricType.METER, metricRegistry.getMeters(filter)); result.set(index_1.MetricType.TIMER, metricRegistry.getTimers(filter)); return result; } getAllCategoryMetrics(filter = index_1.MetricFilter.ALL) { const result = new Map(); const allMetricsRegistry = this.getAllMetricsRegistry(); result.set(index_1.MetricType.GAUGE, allMetricsRegistry.getGauges(filter)); result.set(index_1.MetricType.COUNTER, allMetricsRegistry.getCounters(filter)); result.set(index_1.MetricType.HISTOGRAM, allMetricsRegistry.getHistograms(filter)); result.set(index_1.MetricType.METER, allMetricsRegistry.getMeters(filter)); result.set(index_1.MetricType.TIMER, allMetricsRegistry.getTimers(filter)); return result; } listMetricGroups() { return Array.from(this.metricRegistryMap.keys()); } isEnabled() { return !!this.enabled; } setEnabled(enabled) { this.enabled = enabled; } setLogger(logger) { this.logger = logger; } listMetricNamesByGroup() { if (!this.enabled) { return new Map(); } let result = new Map(); for (let [group, metricRegistry] of this.metricRegistryMap.entries()) { result.set(group, metricRegistry.getMetricNames()); } return result; } getMeter(group, name) { const meter = this.getMetricRegistryByGroup(group).meter(name); this.allMetricsRegistry.register(name, meter); return meter; } getCounter(group, name) { const counter = this.getMetricRegistryByGroup(group).counter(name); this.allMetricsRegistry.register(name, counter); return counter; } getHistogram(group, name) { const histogram = this.getMetricRegistryByGroup(group).histogram(name); this.allMetricsRegistry.register(name, histogram); return histogram; } getTimer(group, name) { const timer = this.getMetricRegistryByGroup(group).timer(name); this.allMetricsRegistry.register(name, timer); return timer; } destory() { this.messengerServer.close(); for (let client of this.metricsClients.values()) { client.close(); } MetricsServerManager.instance = null; } getNewMetricRegistry() { return new index_1.MetricsRegistry(); } } exports.MetricsServerManager = MetricsServerManager; //# sourceMappingURL=MetricsServerManager.js.map