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 }