github.com/polarismesh/polaris@v1.17.8/plugin/statis/prometheus/statis.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package prometheus
    19  
    20  import (
    21  	"context"
    22  	"time"
    23  
    24  	"github.com/prometheus/client_golang/prometheus"
    25  
    26  	"github.com/polarismesh/polaris/common/log"
    27  	"github.com/polarismesh/polaris/common/metrics"
    28  	"github.com/polarismesh/polaris/common/utils"
    29  	"github.com/polarismesh/polaris/plugin"
    30  	"github.com/polarismesh/polaris/plugin/statis/base"
    31  )
    32  
    33  const (
    34  	PluginName = "prometheus"
    35  )
    36  
    37  func init() {
    38  	s := &StatisWorker{}
    39  	plugin.RegisterPlugin(s.Name(), s)
    40  }
    41  
    42  // PrometheusStatis is a struct for prometheus statistics
    43  type StatisWorker struct {
    44  	*base.BaseWorker
    45  	cancel           context.CancelFunc
    46  	discoveryHandler *discoveryMetricHandle
    47  	configHandler    *configMetricHandle
    48  	metricVecCaches  map[string]*prometheus.GaugeVec
    49  }
    50  
    51  // Name 获取统计插件名称
    52  func (s *StatisWorker) Name() string {
    53  	return PluginName
    54  }
    55  
    56  // Initialize 初始化统计插件
    57  func (s *StatisWorker) Initialize(conf *plugin.ConfigEntry) error {
    58  	ctx, cancel := context.WithCancel(context.Background())
    59  	s.cancel = cancel
    60  	s.metricVecCaches = make(map[string]*prometheus.GaugeVec)
    61  	s.discoveryHandler = &discoveryMetricHandle{}
    62  	s.configHandler = &configMetricHandle{}
    63  	if err := s.registerMetrics(); err != nil {
    64  		return err
    65  	}
    66  
    67  	// 设置统计打印周期
    68  	interval, _ := conf.Option["interval"].(int)
    69  	if interval == 0 {
    70  		interval = 60
    71  	}
    72  
    73  	baseWorker, err := base.NewBaseWorker(ctx, s.metricsHandle)
    74  	if err != nil {
    75  		cancel()
    76  		return err
    77  	}
    78  	s.BaseWorker = baseWorker
    79  
    80  	go s.Run(ctx, time.Duration(interval)*time.Second)
    81  	return nil
    82  }
    83  
    84  // Destroy 销毁统计插件
    85  func (s *StatisWorker) Destroy() error {
    86  	return nil
    87  }
    88  
    89  // registerMetrics Registers the interface invocation-related observability metrics
    90  func (s *StatisWorker) registerMetrics() error {
    91  	for _, desc := range base.MetricDescList {
    92  		var collector prometheus.Collector
    93  		switch desc.MetricType {
    94  		case base.TypeForGaugeVec:
    95  			collector = prometheus.NewGaugeVec(prometheus.GaugeOpts{
    96  				Name: desc.Name,
    97  				Help: desc.Help,
    98  				ConstLabels: prometheus.Labels{
    99  					metrics.LabelServerNode: utils.LocalHost,
   100  				},
   101  			}, desc.LabelNames)
   102  			s.metricVecCaches[desc.Name] = collector.(*prometheus.GaugeVec)
   103  		default:
   104  			continue
   105  		}
   106  
   107  		if err := metrics.GetRegistry().Register(collector); err != nil {
   108  			log.Errorf("[APICall] register prometheus collector error, %v", err)
   109  			return err
   110  		}
   111  	}
   112  	return nil
   113  }
   114  
   115  // ReportCallMetrics report call metrics info
   116  func (s *StatisWorker) ReportCallMetrics(metric metrics.CallMetric) {
   117  	s.BaseWorker.ReportCallMetrics(metric)
   118  }
   119  
   120  // ReportDiscoveryMetrics report discovery metrics
   121  func (s *StatisWorker) ReportDiscoveryMetrics(metric ...metrics.DiscoveryMetric) {
   122  	s.discoveryHandler.handle(metric)
   123  }
   124  
   125  // ReportConfigMetrics report config_center metrics
   126  func (s *StatisWorker) ReportConfigMetrics(metric ...metrics.ConfigMetrics) {
   127  	s.configHandler.handle(metric)
   128  }
   129  
   130  // ReportDiscoverCall report discover service times
   131  func (s *StatisWorker) ReportDiscoverCall(service, namespace string, ttMill int64) {
   132  	// ignore not support this
   133  }
   134  
   135  func (a *StatisWorker) metricsHandle(mt metrics.CallMetricType, start time.Time,
   136  	staticsSlice []*base.APICallStatisItem) {
   137  	if mt != metrics.ServerCallMetric {
   138  		return
   139  	}
   140  	if len(staticsSlice) == 0 {
   141  		return
   142  	}
   143  
   144  	// 每一个接口,共 metricsNumber 个指标,下面的指标的个数调整时,这里的 metricsNumber 也需要调整
   145  	statInfos := make([]*base.MetricData, 0, len(staticsSlice)*base.MetricsNumber)
   146  
   147  	for _, item := range staticsSlice {
   148  		var (
   149  			maxTime, avgTime, rqTime, rqCount, minTime float64
   150  			deleteFlag                                 bool
   151  		)
   152  
   153  		if item.Count == 0 && item.ZeroDuration > base.MaxZeroDuration {
   154  			deleteFlag = true
   155  		} else {
   156  			maxTime = float64(item.MaxTime) / 1e6
   157  			minTime = float64(item.MinTime) / 1e6
   158  			rqTime = float64(item.AccTime) / 1e6
   159  			rqCount = float64(item.Count)
   160  			if item.Count > 0 {
   161  				avgTime = float64(item.AccTime) / float64(item.Count) / 1e6
   162  			}
   163  			deleteFlag = false
   164  		}
   165  
   166  		statInfos = append(statInfos, &base.MetricData{
   167  			Name:       base.MetricForClientRqTimeoutMax,
   168  			Data:       maxTime,
   169  			Labels:     base.BuildMetricLabels(item),
   170  			DeleteFlag: deleteFlag,
   171  		}, &base.MetricData{
   172  			Name:       base.MetricForClientRqTimeoutAvg,
   173  			Data:       avgTime,
   174  			Labels:     base.BuildMetricLabels(item),
   175  			DeleteFlag: deleteFlag,
   176  		}, &base.MetricData{
   177  			Name:       base.MetricForClientRqTimeout,
   178  			Data:       rqTime,
   179  			Labels:     base.BuildMetricLabels(item),
   180  			DeleteFlag: deleteFlag,
   181  		}, &base.MetricData{
   182  			Name:       base.MetricForClientRqIntervalCount,
   183  			Data:       rqCount,
   184  			Labels:     base.BuildMetricLabels(item),
   185  			DeleteFlag: deleteFlag,
   186  		}, &base.MetricData{
   187  			Name:       base.MetricForClientRqTimeoutMin,
   188  			Data:       minTime,
   189  			Labels:     base.BuildMetricLabels(item),
   190  			DeleteFlag: deleteFlag,
   191  		},
   192  		)
   193  	}
   194  
   195  	a.reportToPrometheus(statInfos)
   196  }
   197  
   198  // collectMetricData
   199  func (s *StatisWorker) reportToPrometheus(statInfos []*base.MetricData) {
   200  	if len(statInfos) == 0 {
   201  		return
   202  	}
   203  
   204  	// prometheus-sdk 本身做了pull时数据一致性的保证,这里不需要自己在进行额外的保护动作
   205  	// 清理掉当前的存量数据
   206  	for _, statInfo := range statInfos {
   207  		if len(statInfo.Labels) == 0 {
   208  			statInfo.Labels = make(map[string]string)
   209  		}
   210  
   211  		metricVec, ok := s.metricVecCaches[statInfo.Name]
   212  		if !ok {
   213  			continue
   214  		}
   215  
   216  		if statInfo.DeleteFlag {
   217  			metricVec.Delete(statInfo.Labels)
   218  		} else {
   219  			metricVec.With(statInfo.Labels).Set(statInfo.Data)
   220  		}
   221  	}
   222  }