dubbo.apache.org/dubbo-go/v3@v3.1.1/metrics/rpc/collector.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package rpc
    19  
    20  import (
    21  	"github.com/dubbogo/gost/log/logger"
    22  )
    23  
    24  import (
    25  	"dubbo.apache.org/dubbo-go/v3/common"
    26  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    27  	"dubbo.apache.org/dubbo-go/v3/metrics"
    28  )
    29  
    30  var (
    31  	rpcMetricsChan = make(chan metrics.MetricsEvent, 1024)
    32  )
    33  
    34  // init will add the rpc collectorFunc to metrics.collectors slice, and lazy start the rpc collector goroutine
    35  func init() {
    36  	collectorFunc := func(registry metrics.MetricRegistry, url *common.URL) {
    37  		if url.GetParamBool(constant.RpcEnabledKey, true) {
    38  			rc := &rpcCollector{
    39  				registry:  registry,
    40  				metricSet: buildMetricSet(registry),
    41  			}
    42  			go rc.start()
    43  		}
    44  	}
    45  
    46  	metrics.AddCollector("rpc", collectorFunc)
    47  }
    48  
    49  // rpcCollector is a collector which will collect the rpc metrics
    50  type rpcCollector struct {
    51  	registry  metrics.MetricRegistry
    52  	metricSet *metricSet // metricSet is a struct which contains all metrics about rpc
    53  }
    54  
    55  // start will subscribe the rpc.metricsEvent from channel rpcMetricsChan, and handle the event from the channel
    56  func (c *rpcCollector) start() {
    57  	metrics.Subscribe(constant.MetricsRpc, rpcMetricsChan)
    58  	for event := range rpcMetricsChan {
    59  		if rpcEvent, ok := event.(*metricsEvent); ok {
    60  			switch rpcEvent.name {
    61  			case BeforeInvoke:
    62  				c.beforeInvokeHandler(rpcEvent)
    63  			case AfterInvoke:
    64  				c.afterInvokeHandler(rpcEvent)
    65  			default:
    66  			}
    67  		} else {
    68  			logger.Error("Bad metrics event found in RPC collector")
    69  		}
    70  	}
    71  }
    72  
    73  func (c *rpcCollector) beforeInvokeHandler(event *metricsEvent) {
    74  	url := event.invoker.GetURL()
    75  	role := getRole(url)
    76  
    77  	if role == "" {
    78  		return
    79  	}
    80  	labels := buildLabels(url, event.invocation)
    81  	c.recordQps(role, labels)
    82  	c.incRequestsProcessingTotal(role, labels)
    83  }
    84  
    85  func (c *rpcCollector) afterInvokeHandler(event *metricsEvent) {
    86  	url := event.invoker.GetURL()
    87  	role := getRole(url)
    88  
    89  	if role == "" {
    90  		return
    91  	}
    92  	labels := buildLabels(url, event.invocation)
    93  	c.incRequestsTotal(role, labels)
    94  	c.decRequestsProcessingTotal(role, labels)
    95  	if event.result != nil {
    96  		if event.result.Error() == nil {
    97  			c.incRequestsSucceedTotal(role, labels)
    98  		} else {
    99  			// TODO: Breaking down RPC exceptions further
   100  			c.incRequestsFailedTotal(role, labels)
   101  		}
   102  	}
   103  	c.reportRTMilliseconds(role, labels, event.costTime.Milliseconds())
   104  }
   105  
   106  func (c *rpcCollector) recordQps(role string, labels map[string]string) {
   107  	switch role {
   108  	case constant.SideProvider:
   109  		c.metricSet.provider.qpsTotal.Record(labels)
   110  	case constant.SideConsumer:
   111  		c.metricSet.consumer.qpsTotal.Record(labels)
   112  	}
   113  }
   114  
   115  func (c *rpcCollector) incRequestsTotal(role string, labels map[string]string) {
   116  	switch role {
   117  	case constant.SideProvider:
   118  		c.metricSet.provider.requestsTotal.Inc(labels)
   119  		c.metricSet.provider.requestsTotalAggregate.Inc(labels)
   120  	case constant.SideConsumer:
   121  		c.metricSet.consumer.requestsTotal.Inc(labels)
   122  		c.metricSet.consumer.requestsTotalAggregate.Inc(labels)
   123  	}
   124  }
   125  
   126  func (c *rpcCollector) incRequestsProcessingTotal(role string, labels map[string]string) {
   127  	switch role {
   128  	case constant.SideProvider:
   129  		c.metricSet.provider.requestsProcessingTotal.Inc(labels)
   130  	case constant.SideConsumer:
   131  		c.metricSet.consumer.requestsProcessingTotal.Inc(labels)
   132  	}
   133  }
   134  
   135  func (c *rpcCollector) decRequestsProcessingTotal(role string, labels map[string]string) {
   136  	switch role {
   137  	case constant.SideProvider:
   138  		c.metricSet.provider.requestsProcessingTotal.Dec(labels)
   139  	case constant.SideConsumer:
   140  		c.metricSet.consumer.requestsProcessingTotal.Dec(labels)
   141  	}
   142  }
   143  
   144  func (c *rpcCollector) incRequestsSucceedTotal(role string, labels map[string]string) {
   145  	switch role {
   146  	case constant.SideProvider:
   147  		c.metricSet.provider.requestsSucceedTotal.Inc(labels)
   148  		c.metricSet.provider.requestsSucceedTotalAggregate.Inc(labels)
   149  	case constant.SideConsumer:
   150  		c.metricSet.consumer.requestsSucceedTotal.Inc(labels)
   151  		c.metricSet.consumer.requestsSucceedTotalAggregate.Inc(labels)
   152  	}
   153  }
   154  
   155  func (c *rpcCollector) incRequestsFailedTotal(role string, labels map[string]string) {
   156  	switch role {
   157  	case constant.SideProvider:
   158  		c.metricSet.provider.requestsFailedTotal.Inc(labels)
   159  		c.metricSet.provider.requestsFailedTotalAggregate.Inc(labels)
   160  	case constant.SideConsumer:
   161  		c.metricSet.consumer.requestsFailedTotal.Inc(labels)
   162  		c.metricSet.consumer.requestsFailedTotalAggregate.Inc(labels)
   163  	}
   164  }
   165  
   166  func (c *rpcCollector) reportRTMilliseconds(role string, labels map[string]string, cost int64) {
   167  	switch role {
   168  	case constant.SideProvider:
   169  		c.metricSet.provider.rtMilliseconds.Record(labels, float64(cost))
   170  		c.metricSet.provider.rtMillisecondsAggregate.Record(labels, float64(cost))
   171  		c.metricSet.provider.rtMillisecondsQuantiles.Record(labels, float64(cost))
   172  	case constant.SideConsumer:
   173  		c.metricSet.consumer.rtMilliseconds.Record(labels, float64(cost))
   174  		c.metricSet.consumer.rtMillisecondsAggregate.Record(labels, float64(cost))
   175  		c.metricSet.consumer.rtMillisecondsQuantiles.Record(labels, float64(cost))
   176  	}
   177  }