import { IMetricsRegistry , Metric , MetricName , MetricSet , MetricsRegistry , MetricType } from './common' ; import { ProxyCreateMessage , ProxyUpdateMessage } from './domain' ; import { MetricsConstants } from './MetricsConstants' ; import { Environment , EnvironmentUtil } from 'pandora-env' ; import { MetricsMessengerClient } from './util/MessengerUtil' ; import { Counter , FastCompass , Gauge , Histogram , Meter , Proxiable , Timer } from './client' ; import { AbstractIndicator } from './indicator/AbstractIndicator' ; export class MetricsClient extends AbstractIndicator { environment : Environment = EnvironmentUtil . getInstance ( ) . getCurrentEnvironment ( ) ; static getInstance ( ) { if ( ! this . instance ) { this . instance = new MetricsClient ( ) ; } return this . instance ; } appName : string = this . getAppName ( ) ; allMetricsRegistry : IMetricsRegistry = this . getNewMetricRegistry ( ) ; protected messengerClient : MetricsMessengerClient = new MetricsMessengerClient ( MetricsConstants . METRICS_PANDORA_KEY ) ; clientId : string = Math . random ( ) . toString ( 35 ) . substr ( 2 , 10 ) ; group = 'metrics' ; debug = require ( 'debug' ) ( 'pandora:metrics:client:' + this . clientId ) ; static instance : MetricsClient ; constructor ( ) { super ( ) ; this . registerClient ( ) ; this . registerDownlink ( ) ; } /**
     * 注册 Client
     */ protected registerClient ( ) { this . messengerClient . register ( { appName : this . appName , clientId : this . clientId , } ) ; } example param { string } group param { } name param { Proxiable } metric register ( group , name , metric ) { this . debug ( `Register: wait register a metrics name = ${ name }` ) ; let newName = this . buildName ( name ) ; newName = newName . tagged ( 'appName' , this . getAppName ( ) ) ; if ( typeof metric === 'string' ) { let newMetric = this . allMetricsRegistry . getMetric ( newName ) ; if ( newMetric ) { return newMetric ; } else { metric = this . createMetricProxy ( metric ) ; } } if ( ! metric . type ) { metric . type = MetricType . GAUGE ; } this . allMetricsRegistry . register ( newName , < Metric > < any > metric ) ; if ( ( < Proxiable > metric ) . proxyMethod && ( < Proxiable > metric ) . proxyMethod . length ) { for ( let method of ( < Proxiable > metric ) . proxyMethod ) { metric [ method ] = ( ... args ) => { this . debug ( `Invoke: invoke name = ${ newName . getNameKey ( ) }, type = ${ ( < Proxiable > metric ) . type }, method = ${ method }, value = ${ args }` ) ; this . report ( { action : MetricsConstants . EVT_METRIC_UPDATE , name : newName . getNameKey ( ) , method : method , value : args , type : ( < Proxiable > metric ) . type , clientId : this . clientId } ) ; } ; } } if ( metric instanceof MetricSet ) { for ( let subMetric of metric . getMetrics ( ) ) { this . reportMetric ( MetricName . join ( newName , subMetric . name ) , subMetric . metric , group ) ; } } else { this . reportMetric ( newName , metric , group ) ; } return metric ; } reportMetric ( name , metric , group ) { this . report ( { action : MetricsConstants . EVT_METRIC_CREATE , name : name . getNameKey ( ) , type : metric . type , group : group , clientId : this . clientId } ) ; } param data report ( data ) { this . messengerClient . report ( this . getClientUplinkKey ( ) , data ) ; } async invoke ( args ) { this . debug ( `Invoke: invoked, key = ${ args . metricKey } ` ) ; let metric = this . allMetricsRegistry . getMetric ( MetricName . parseKey ( args . metricKey ) ) ; if ( metric && metric . type === args . type ) { return await Promise . resolve ( ( < Gauge < any > > metric ) . getValue ( ) ) ; } else { this . debug ( `Invoke: can not find metric(${ args . metricKey }) or type different` ) ; } } /**
     * 注册下行链路
     */ protected registerDownlink ( ) { this . debug ( `Register: down link eventKey = ${ this . getClientDownlinkKey ( ) }` ) ; this . messengerClient . query ( this . getClientDownlinkKey ( ) , async ( message , reply ) => { try { reply && reply ( await this . invoke ( message ) ) ; } catch ( err ) { this . debug ( `Error: err = ${ err }` ) ; reply && reply ( ) ; } } ) ; } protected getAppName ( ) { return this . environment . get ( 'appName' ) ; } getCounter ( group , name ) { return this . register ( group , name , 'COUNTER' ) ; } getTimer ( group , name ) { return this . register ( group , name , 'TIMER' ) ; } getMeter ( group , name ) { return this . register ( group , name , 'METER' ) ; } getHistogram ( group , name ) { return this . register ( group , name , 'HISTOGRAM' ) ; } getFastCompass ( group , name ) { return this . register ( group , name , 'FASTCOMPASS' ) ; } private buildName ( name ) { if ( typeof name === 'string' ) { name = MetricName . build ( < string > name ) ; } return < MetricName > name ; } getNewMetricRegistry ( ) { return new MetricsRegistry ( ) ; } private createMetricProxy ( type ) { switch ( type ) { case 'COUNTER' : return new Counter ( ) ; case 'METER' : return new Meter ( ) ; case 'TIMER' : return new Timer ( ) ; case 'HISTOGRAM' : return new Histogram ( ) ; case 'FASTCOMPASS' : return new FastCompass ( ) ; } } }