package server import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "net/http" ) var rpcCallCnt = &Metric{ ID: "rpcCallCnt", Name: "rpc_call_total", Description: "HOW MANY RPC CALL", Type: "counter_vec", Args: []string{"service"}, } var rpcCallDur = &Metric{ ID: "rpc_call_duration", Name: "rpc_call_duration_seconds", Description: "rpc call duration seconds", Type: "histogram_vec", Args: []string{"client", "server", "method"}, } var standardMetrics = []*Metric{ rpcCallCnt, rpcCallDur, } type Metric struct { MetricCollector prometheus.Collector ID string Name string Description string Type string Args []string } type Prometheus struct { MetricsList []*Metric MetricsPath string CallCnt *prometheus.CounterVec CallDur *prometheus.HistogramVec } func NewPrometheus(subsystem string, customMetricsList ...*Metric) *Prometheus { var metricsList []*Metric for _, v := range customMetricsList { metricsList = append(metricsList, v) } for _, metric := range standardMetrics { metricsList = append(metricsList, metric) } p := &Prometheus{ MetricsList: metricsList, MetricsPath: "/metrics", } p.registerMetrics(subsystem) return p } func (p *Prometheus) Start(addr string) error { http.Handle(p.MetricsPath, promhttp.Handler()) return http.ListenAndServe(addr, nil) } func (p *Prometheus) RegisterMetrics(sub string, metrics ...*Metric) { for _, m := range metrics { metric := NewMetric(m, sub) if err := prometheus.Register(metric); err != nil { Log.Errorf("%s could not be registered in prometheus", m.Name) } m.MetricCollector = metric } } // NewMetric associates prometheus.Collector based on Metric.Type func NewMetric(m *Metric, subsystem string) prometheus.Collector { var metric prometheus.Collector switch m.Type { case "counter_vec": metric = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: m.Name, Help: m.Description, }, m.Args, ) case "counter": metric = prometheus.NewCounter( prometheus.CounterOpts{ Name: m.Name, Help: m.Description, }, ) case "gauge_vec": metric = prometheus.NewGaugeVec( prometheus.GaugeOpts{ Name: m.Name, Help: m.Description, }, m.Args, ) case "gauge": metric = prometheus.NewGauge( prometheus.GaugeOpts{ Name: m.Name, Help: m.Description, }, ) case "histogram_vec": metric = prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: m.Name, Help: m.Description, }, m.Args, ) case "histogram": metric = prometheus.NewHistogram( prometheus.HistogramOpts{ Name: m.Name, Help: m.Description, }, ) case "summary_vec": metric = prometheus.NewSummaryVec( prometheus.SummaryOpts{ Name: m.Name, Help: m.Description, }, m.Args, ) case "summary": metric = prometheus.NewSummary( prometheus.SummaryOpts{ Name: m.Name, Help: m.Description, }, ) } return metric } func (p *Prometheus) registerMetrics(sub string) { for _, metricDef := range p.MetricsList { metric := NewMetric(metricDef, sub) if err := prometheus.Register(metric); err != nil { Log.Errorf("%s could not be registered in prometheus", metricDef.Name) } switch metricDef { case rpcCallCnt: p.CallCnt = metric.(*prometheus.CounterVec) case rpcCallDur: p.CallDur = metric.(*prometheus.HistogramVec) } metricDef.MetricCollector = metric } }