pandora-metrics
Version: 
## Overview
331 lines • 13.1 kB
JavaScript
;
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