This is an automated email from the ASF dual-hosted git repository.
justxuewei pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git
The following commit(s) were added to refs/heads/main by this push:
new f6fdbfdf7 feat: add some metrics about RT (#2340)
f6fdbfdf7 is described below
commit f6fdbfdf772ad7f82ea64b8d861e4140c3fa17cb
Author: Wang Guan <[email protected]>
AuthorDate: Tue Jul 4 13:34:20 2023 +0800
feat: add some metrics about RT (#2340)
* feat: add min RT metrics
* refactor: adapt to Go 1.17 and bundle gaugeVec with syncMap
* feat: add max and sum RT metrics
* feat: avg RT metrics
* refactor: RT sum metrics
* feat: last RT metrics
* refactor: file names and method names
---
metrics/prometheus/after_invocation.go | 49 ---------
metrics/prometheus/before_invocation.go | 40 --------
metrics/prometheus/constant.go | 8 +-
metrics/prometheus/metric_set.go | 72 ++++++++------
metrics/prometheus/{common.go => model.go} | 155 ++++++++++++++++++++---------
metrics/prometheus/reporter.go | 79 ++++++++++++---
metrics/prometheus/util.go | 75 ++++++++++++++
7 files changed, 294 insertions(+), 184 deletions(-)
diff --git a/metrics/prometheus/after_invocation.go
b/metrics/prometheus/after_invocation.go
deleted file mode 100644
index f1235a2d7..000000000
--- a/metrics/prometheus/after_invocation.go
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package prometheus
-
-import (
- "context"
- "time"
-)
-
-import (
- "dubbo.apache.org/dubbo-go/v3/protocol"
-)
-
-func (reporter *PrometheusReporter) ReportAfterInvocation(ctx context.Context,
invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration,
res protocol.Result) {
- if !reporter.reporterConfig.Enable {
- return
- }
- url := invoker.GetURL()
-
- role := getRole(url)
- if role == "" {
- return
- }
- labels := buildLabels(url)
-
- reporter.reportRTSummaryVec(role, &labels, cost.Milliseconds())
- reporter.reportRequestsTotalCounterVec(role, &labels)
- reporter.decRequestsProcessingTotalGaugeVec(role, &labels)
-
- if res != nil && res.Error() == nil {
- // succeed
- reporter.incRequestsSucceedTotalCounterVec(role, &labels)
- }
-}
diff --git a/metrics/prometheus/before_invocation.go
b/metrics/prometheus/before_invocation.go
deleted file mode 100644
index 7477b1362..000000000
--- a/metrics/prometheus/before_invocation.go
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package prometheus
-
-import (
- "context"
-)
-import (
- "dubbo.apache.org/dubbo-go/v3/protocol"
-)
-
-func (reporter *PrometheusReporter) ReportBeforeInvocation(ctx
context.Context, invoker protocol.Invoker, invocation protocol.Invocation) {
- if !reporter.reporterConfig.Enable {
- return
- }
- url := invoker.GetURL()
-
- role := getRole(url)
- if role == "" {
- return
- }
- labels := buildLabels(url)
-
- reporter.incRequestsProcessingTotalGaugeVec(role, &labels)
-}
diff --git a/metrics/prometheus/constant.go b/metrics/prometheus/constant.go
index 95e090d46..35858853f 100644
--- a/metrics/prometheus/constant.go
+++ b/metrics/prometheus/constant.go
@@ -34,12 +34,14 @@ const (
requestsField = "requests"
rtField = "rt"
- tpsField = "tps"
milliSecondsField = "milliseconds"
- counterField = "counter"
- summaryField = "summary"
+ minField = "min"
+ maxField = "max"
+ sumField = "sum"
+ avgField = "avg"
+ lastField = "last"
totalField = "total"
processingField = "processing"
diff --git a/metrics/prometheus/metric_set.go b/metrics/prometheus/metric_set.go
index 79c020369..115c6ca3d 100644
--- a/metrics/prometheus/metric_set.go
+++ b/metrics/prometheus/metric_set.go
@@ -29,40 +29,56 @@ import (
"dubbo.apache.org/dubbo-go/v3/metrics"
)
-// metricSet is a set of metrics that are reported to prometheus in dubbo go
+// metricSet is a set of metrics that are reported to prometheus in dubbo-go
type metricSet struct {
- // report the consumer-side's rt gauge data
- consumerRTSummaryVec *prometheus.SummaryVec
- // report the provider-side's rt gauge data
- providerRTSummaryVec *prometheus.SummaryVec
+ provider providerMetrics
+ consumer consumerMetrics
+}
+
+func (ms *metricSet) init(reporterConfig *metrics.ReporterConfig) {
+ ms.provider.init(reporterConfig)
+ ms.consumer.init(reporterConfig)
+}
- // report the provider-side's request total counter data
- providerRequestsTotalCounterVec *prometheus.CounterVec
- // report the provider-side's processing request counter data
- providerRequestsProcessingTotalGaugeVec *prometheus.GaugeVec
- // The number of requests successfully received by the provider
- providerRequestsSucceedTotalCounterVec *prometheus.CounterVec
+type rpcCommonMetrics struct {
+ requestsTotal *prometheus.CounterVec
+ requestsProcessingTotal *prometheus.GaugeVec
+ requestsSucceedTotal *prometheus.CounterVec
+ rtMillisecondsMin *GaugeVecWithSyncMap
+ rtMillisecondsMax *GaugeVecWithSyncMap
+ rtMillisecondsSum *prometheus.CounterVec
+ rtMillisecondsAvg *GaugeVecWithSyncMap
+ rtMillisecondsLast *prometheus.GaugeVec
+}
- // report the consumer-side's request total counter data
- consumerRequestsTotalCounterVec *prometheus.CounterVec
- // report the consumer-side's processing request counter data
- consumerRequestsProcessingTotalGaugeVec *prometheus.GaugeVec
- // The number of successful requests sent by consumers
- consumerRequestsSucceedTotalCounterVec *prometheus.CounterVec
+type providerMetrics struct {
+ rpcCommonMetrics
}
-var labelNames = []string{applicationNameKey, groupKey, hostnameKey,
interfaceKey, ipKey, methodKey, versionKey}
+func (pm *providerMetrics) init(reporterConfig *metrics.ReporterConfig) {
+ pm.requestsTotal = newAutoCounterVec(buildMetricsName(providerField,
requestsField, totalField), reporterConfig.Namespace, labelNames)
+ pm.requestsProcessingTotal =
newAutoGaugeVec(buildMetricsName(providerField, requestsField, processingField,
totalField), reporterConfig.Namespace, labelNames)
+ pm.requestsSucceedTotal =
newAutoCounterVec(buildMetricsName(providerField, requestsField, succeedField,
totalField), reporterConfig.Namespace, labelNames)
+ pm.rtMillisecondsMin =
newAutoGaugeVecWithSyncMap(buildMetricsName(providerField, rtField,
milliSecondsField, minField), reporterConfig.Namespace, labelNames)
+ pm.rtMillisecondsMax =
newAutoGaugeVecWithSyncMap(buildMetricsName(providerField, rtField,
milliSecondsField, maxField), reporterConfig.Namespace, labelNames)
+ pm.rtMillisecondsSum =
newAutoCounterVec(buildMetricsName(providerField, rtField, milliSecondsField,
sumField), reporterConfig.Namespace, labelNames)
+ pm.rtMillisecondsAvg =
newAutoGaugeVecWithSyncMap(buildMetricsName(providerField, rtField,
milliSecondsField, avgField), reporterConfig.Namespace, labelNames)
+ pm.rtMillisecondsLast = newAutoGaugeVec(buildMetricsName(providerField,
rtField, milliSecondsField, lastField), reporterConfig.Namespace, labelNames)
+}
+
+type consumerMetrics struct {
+ rpcCommonMetrics
+}
-// init metric set and register to prometheus
-func (ms *metricSet) initAndRegister(reporterConfig *metrics.ReporterConfig) {
- ms.consumerRTSummaryVec =
newAutoSummaryVec(buildMetricsName(consumerField, rtField, milliSecondsField,
summaryField), reporterConfig.Namespace, labelNames,
reporterConfig.SummaryMaxAge)
- ms.providerRTSummaryVec =
newAutoSummaryVec(buildMetricsName(providerField, rtField, milliSecondsField,
summaryField), reporterConfig.Namespace, labelNames,
reporterConfig.SummaryMaxAge)
- ms.consumerRequestsTotalCounterVec =
newAutoCounterVec(buildMetricsName(consumerField, requestsField, totalField),
reporterConfig.Namespace, labelNames)
- ms.providerRequestsTotalCounterVec =
newAutoCounterVec(buildMetricsName(providerField, requestsField, totalField),
reporterConfig.Namespace, labelNames)
- ms.consumerRequestsProcessingTotalGaugeVec =
newAutoGaugeVec(buildMetricsName(consumerField, requestsField, processingField,
totalField), reporterConfig.Namespace, labelNames)
- ms.providerRequestsProcessingTotalGaugeVec =
newAutoGaugeVec(buildMetricsName(providerField, requestsField, processingField,
totalField), reporterConfig.Namespace, labelNames)
- ms.consumerRequestsSucceedTotalCounterVec =
newAutoCounterVec(buildMetricsName(consumerField, requestsField, succeedField,
totalField), reporterConfig.Namespace, labelNames)
- ms.providerRequestsSucceedTotalCounterVec =
newAutoCounterVec(buildMetricsName(providerField, requestsField, succeedField,
totalField), reporterConfig.Namespace, labelNames)
+func (cm *consumerMetrics) init(reporterConfig *metrics.ReporterConfig) {
+ cm.requestsTotal = newAutoCounterVec(buildMetricsName(consumerField,
requestsField, totalField), reporterConfig.Namespace, labelNames)
+ cm.requestsProcessingTotal =
newAutoGaugeVec(buildMetricsName(consumerField, requestsField, processingField,
totalField), reporterConfig.Namespace, labelNames)
+ cm.requestsSucceedTotal =
newAutoCounterVec(buildMetricsName(consumerField, requestsField, succeedField,
totalField), reporterConfig.Namespace, labelNames)
+ cm.rtMillisecondsMin =
newAutoGaugeVecWithSyncMap(buildMetricsName(consumerField, rtField,
milliSecondsField, minField), reporterConfig.Namespace, labelNames)
+ cm.rtMillisecondsMax =
newAutoGaugeVecWithSyncMap(buildMetricsName(consumerField, rtField,
milliSecondsField, maxField), reporterConfig.Namespace, labelNames)
+ cm.rtMillisecondsSum =
newAutoCounterVec(buildMetricsName(consumerField, rtField, milliSecondsField,
sumField), reporterConfig.Namespace, labelNames)
+ cm.rtMillisecondsAvg =
newAutoGaugeVecWithSyncMap(buildMetricsName(consumerField, rtField,
milliSecondsField, avgField), reporterConfig.Namespace, labelNames)
+ cm.rtMillisecondsLast = newAutoGaugeVec(buildMetricsName(consumerField,
rtField, milliSecondsField, lastField), reporterConfig.Namespace, labelNames)
}
func buildMetricsName(args ...string) string {
diff --git a/metrics/prometheus/common.go b/metrics/prometheus/model.go
similarity index 57%
rename from metrics/prometheus/common.go
rename to metrics/prometheus/model.go
index 32137d1e2..d62734f8f 100644
--- a/metrics/prometheus/common.go
+++ b/metrics/prometheus/model.go
@@ -18,63 +18,17 @@
package prometheus
import (
- "strconv"
"strings"
+ "sync"
+ "sync/atomic"
"time"
)
import (
- "github.com/dubbogo/gost/log/logger"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
-import (
- "dubbo.apache.org/dubbo-go/v3/common"
- "dubbo.apache.org/dubbo-go/v3/common/constant"
-)
-
-var (
- defaultHistogramBucket = []float64{10, 50, 100, 200, 500, 1000, 10000}
-)
-
-func buildLabels(url *common.URL) prometheus.Labels {
- return prometheus.Labels{
- applicationNameKey: url.GetParam(constant.ApplicationKey, ""),
- groupKey: url.Group(),
- hostnameKey: "not implemented yet",
- interfaceKey: url.Service(),
- ipKey: common.GetLocalIp(),
- versionKey: url.GetParam(constant.AppVersionKey, ""),
- methodKey: url.GetParam(constant.MethodKey, ""),
- }
-}
-
-// return the role of the application, provider or consumer, if the url is not
a valid one, return empty string
-func getRole(url *common.URL) (role string) {
- if isProvider(url) {
- role = providerField
- } else if isConsumer(url) {
- role = consumerField
- } else {
- logger.Warnf("The url belongs neither the consumer nor the
provider, "+
- "so the invocation will be ignored. url: %s",
url.String())
- }
- return
-}
-
-// isProvider shows whether this url represents the application received the
request as server
-func isProvider(url *common.URL) bool {
- role := url.GetParam(constant.RegistryRoleKey, "")
- return strings.EqualFold(role, strconv.Itoa(common.PROVIDER))
-}
-
-// isConsumer shows whether this url represents the application sent then
request as client
-func isConsumer(url *common.URL) bool {
- role := url.GetParam(constant.RegistryRoleKey, "")
- return strings.EqualFold(role, strconv.Itoa(common.CONSUMER))
-}
-
func newHistogramVec(name, namespace string, labels []string)
*prometheus.HistogramVec {
return prometheus.NewHistogramVec(
prometheus.HistogramOpts{
@@ -194,3 +148,108 @@ func newAutoSummaryVec(name, namespace string, labels
[]string, maxAge int64) *p
labels,
)
}
+
+type GaugeVecWithSyncMap struct {
+ GaugeVec *prometheus.GaugeVec
+ SyncMap *sync.Map
+}
+
+func newAutoGaugeVecWithSyncMap(name, namespace string, labels []string)
*GaugeVecWithSyncMap {
+ return &GaugeVecWithSyncMap{
+ GaugeVec: newAutoGaugeVec(name, namespace, labels),
+ SyncMap: &sync.Map{},
+ }
+}
+
+func convertLabelsToMapKey(labels prometheus.Labels) string {
+ return strings.Join([]string{
+ labels[applicationNameKey],
+ labels[groupKey],
+ labels[hostnameKey],
+ labels[interfaceKey],
+ labels[ipKey],
+ labels[versionKey],
+ labels[methodKey],
+ }, "_")
+}
+
+func (gv *GaugeVecWithSyncMap) updateMin(labels *prometheus.Labels, curValue
int64) {
+ key := convertLabelsToMapKey(*labels)
+ cur := &atomic.Value{} // for first store
+ cur.Store(curValue)
+ for {
+ if actual, loaded := gv.SyncMap.LoadOrStore(key, cur); loaded {
+ store := actual.(*atomic.Value)
+ storeValue := store.Load().(int64)
+ if curValue < storeValue {
+ if store.CompareAndSwap(storeValue, curValue) {
+ // value is not changed, should update
+
gv.GaugeVec.With(*labels).Set(float64(curValue))
+ break
+ }
+ // value has changed, continue for loop
+ } else {
+ // no need to update
+ break
+ }
+ } else {
+ // store current curValue as this labels' init value
+ gv.GaugeVec.With(*labels).Set(float64(curValue))
+ break
+ }
+ }
+}
+
+func (gv *GaugeVecWithSyncMap) updateMax(labels *prometheus.Labels, curValue
int64) {
+ key := convertLabelsToMapKey(*labels)
+ cur := &atomic.Value{} // for first store
+ cur.Store(curValue)
+ for {
+ if actual, loaded := gv.SyncMap.LoadOrStore(key, cur); loaded {
+ store := actual.(*atomic.Value)
+ storeValue := store.Load().(int64)
+ if curValue > storeValue {
+ if store.CompareAndSwap(storeValue, curValue) {
+ // value is not changed, should update
+
gv.GaugeVec.With(*labels).Set(float64(curValue))
+ break
+ }
+ // value has changed, continue for loop
+ } else {
+ // no need to update
+ break
+ }
+ } else {
+ // store current curValue as this labels' init value
+ gv.GaugeVec.With(*labels).Set(float64(curValue))
+ break
+ }
+ }
+}
+
+func (gv *GaugeVecWithSyncMap) updateAvg(labels *prometheus.Labels, curValue
int64) {
+ key := convertLabelsToMapKey(*labels)
+ cur := &atomic.Value{} // for first store
+ type avgPair struct {
+ Sum int64
+ N int64
+ }
+ cur.Store(avgPair{Sum: curValue, N: 1})
+
+ for {
+ if actual, loaded := gv.SyncMap.LoadOrStore(key, cur); loaded {
+ store := actual.(*atomic.Value)
+ storeValue := store.Load().(avgPair)
+ newValue := avgPair{Sum: storeValue.Sum + curValue, N:
storeValue.N + 1}
+ if store.CompareAndSwap(storeValue, newValue) {
+ // value is not changed, should update
+
gv.GaugeVec.With(*labels).Set(float64(newValue.Sum / newValue.N))
+ break
+ }
+ } else {
+ // store current curValue as this labels' init value
+ gv.GaugeVec.With(*labels).Set(float64(curValue))
+ break
+ }
+ }
+}
diff --git a/metrics/prometheus/reporter.go b/metrics/prometheus/reporter.go
index 8c38c6114..7ca4398bf 100644
--- a/metrics/prometheus/reporter.go
+++ b/metrics/prometheus/reporter.go
@@ -21,6 +21,7 @@ import (
"context"
"net/http"
"sync"
+ "time"
)
import (
@@ -32,6 +33,7 @@ import (
import (
"dubbo.apache.org/dubbo-go/v3/common/extension"
"dubbo.apache.org/dubbo-go/v3/metrics"
+ "dubbo.apache.org/dubbo-go/v3/protocol"
)
var (
@@ -62,7 +64,7 @@ func newPrometheusReporter(reporterConfig
*metrics.ReporterConfig) metrics.Repor
if reporterInstance == nil {
reporterInitOnce.Do(func() {
ms := &metricSet{}
- ms.initAndRegister(reporterConfig)
+ ms.init(reporterConfig)
reporterInstance = &PrometheusReporter{
reporterConfig: reporterConfig,
namespace: reporterConfig.Namespace,
@@ -103,47 +105,92 @@ func (reporter *PrometheusReporter) shutdownServer() {
}
}
-func (reporter *PrometheusReporter) reportRTSummaryVec(role string, labels
*prometheus.Labels, costMs int64) {
+func (reporter *PrometheusReporter) ReportBeforeInvocation(ctx
context.Context, invoker protocol.Invoker, invocation protocol.Invocation) {
+ if !reporter.reporterConfig.Enable {
+ return
+ }
+ url := invoker.GetURL()
+
+ role := getRole(url)
+ if role == "" {
+ return
+ }
+ labels := buildLabels(url)
+
+ reporter.incRequestsProcessingTotal(role, &labels)
+}
+
+func (reporter *PrometheusReporter) ReportAfterInvocation(ctx context.Context,
invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration,
res protocol.Result) {
+ if !reporter.reporterConfig.Enable {
+ return
+ }
+ url := invoker.GetURL()
+
+ role := getRole(url)
+ if role == "" {
+ return
+ }
+ labels := buildLabels(url)
+
+ reporter.incRequestsTotal(role, &labels)
+ reporter.decRequestsProcessingTotal(role, &labels)
+ reporter.reportRTMilliseconds(role, &labels, cost.Milliseconds())
+
+ if res != nil && res.Error() == nil {
+ // succeed
+ reporter.incRequestsSucceedTotal(role, &labels)
+ }
+}
+
+func (reporter *PrometheusReporter) incRequestsTotal(role string, labels
*prometheus.Labels) {
switch role {
case providerField:
-
reporter.providerRTSummaryVec.With(*labels).Observe(float64(costMs))
+ reporter.provider.requestsTotal.With(*labels).Inc()
case consumerField:
-
reporter.consumerRTSummaryVec.With(*labels).Observe(float64(costMs))
+ reporter.consumer.requestsTotal.With(*labels).Inc()
}
}
-func (reporter *PrometheusReporter) reportRequestsTotalCounterVec(role string,
labels *prometheus.Labels) {
+func (reporter *PrometheusReporter) incRequestsProcessingTotal(role string,
labels *prometheus.Labels) {
switch role {
case providerField:
- reporter.providerRequestsTotalCounterVec.With(*labels).Inc()
+ reporter.provider.requestsProcessingTotal.With(*labels).Inc()
case consumerField:
- reporter.consumerRequestsTotalCounterVec.With(*labels).Inc()
+ reporter.consumer.requestsProcessingTotal.With(*labels).Inc()
}
}
-func (reporter *PrometheusReporter) incRequestsProcessingTotalGaugeVec(role
string, labels *prometheus.Labels) {
+func (reporter *PrometheusReporter) decRequestsProcessingTotal(role string,
labels *prometheus.Labels) {
switch role {
case providerField:
-
reporter.providerRequestsProcessingTotalGaugeVec.With(*labels).Inc()
+ reporter.provider.requestsProcessingTotal.With(*labels).Dec()
case consumerField:
-
reporter.consumerRequestsProcessingTotalGaugeVec.With(*labels).Inc()
+ reporter.consumer.requestsProcessingTotal.With(*labels).Dec()
}
}
-func (reporter *PrometheusReporter) decRequestsProcessingTotalGaugeVec(role
string, labels *prometheus.Labels) {
+func (reporter *PrometheusReporter) incRequestsSucceedTotal(role string,
labels *prometheus.Labels) {
switch role {
case providerField:
-
reporter.providerRequestsProcessingTotalGaugeVec.With(*labels).Dec()
+ reporter.provider.requestsSucceedTotal.With(*labels).Inc()
case consumerField:
-
reporter.consumerRequestsProcessingTotalGaugeVec.With(*labels).Dec()
+ reporter.consumer.requestsSucceedTotal.With(*labels).Inc()
}
}
-func (reporter *PrometheusReporter) incRequestsSucceedTotalCounterVec(role
string, labels *prometheus.Labels) {
+func (reporter *PrometheusReporter) reportRTMilliseconds(role string, labels
*prometheus.Labels, costMs int64) {
switch role {
case providerField:
-
reporter.providerRequestsSucceedTotalCounterVec.With(*labels).Inc()
+ go
reporter.provider.rtMillisecondsLast.With(*labels).Set(float64(costMs))
+ go
reporter.provider.rtMillisecondsSum.With(*labels).Add(float64(costMs))
+ go reporter.provider.rtMillisecondsMin.updateMin(labels, costMs)
+ go reporter.provider.rtMillisecondsMax.updateMax(labels, costMs)
+ go reporter.provider.rtMillisecondsAvg.updateAvg(labels, costMs)
case consumerField:
-
reporter.consumerRequestsSucceedTotalCounterVec.With(*labels).Inc()
+ go
reporter.consumer.rtMillisecondsLast.With(*labels).Set(float64(costMs))
+ go
reporter.consumer.rtMillisecondsSum.With(*labels).Add(float64(costMs))
+ go reporter.consumer.rtMillisecondsMin.updateMin(labels, costMs)
+ go reporter.consumer.rtMillisecondsMax.updateMax(labels, costMs)
+ go reporter.consumer.rtMillisecondsAvg.updateAvg(labels, costMs)
}
}
diff --git a/metrics/prometheus/util.go b/metrics/prometheus/util.go
new file mode 100644
index 000000000..4e1a9c8dc
--- /dev/null
+++ b/metrics/prometheus/util.go
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package prometheus
+
+import (
+ "strconv"
+ "strings"
+)
+
+import (
+ "github.com/dubbogo/gost/log/logger"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3/common"
+ "dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+var (
+ labelNames = []string{applicationNameKey, groupKey,
hostnameKey, interfaceKey, ipKey, methodKey, versionKey}
+ defaultHistogramBucket = []float64{10, 50, 100, 200, 500, 1000, 10000}
+)
+
+func buildLabels(url *common.URL) prometheus.Labels {
+ return prometheus.Labels{
+ applicationNameKey: url.GetParam(constant.ApplicationKey, ""),
+ groupKey: url.Group(),
+ hostnameKey: "not implemented yet",
+ interfaceKey: url.Service(),
+ ipKey: common.GetLocalIp(),
+ versionKey: url.GetParam(constant.AppVersionKey, ""),
+ methodKey: url.GetParam(constant.MethodKey, ""),
+ }
+}
+
+// return the role of the application, provider or consumer, if the url is not
a valid one, return empty string
+func getRole(url *common.URL) (role string) {
+ if isProvider(url) {
+ role = providerField
+ } else if isConsumer(url) {
+ role = consumerField
+ } else {
+ logger.Warnf("The url belongs neither the consumer nor the
provider, "+
+ "so the invocation will be ignored. url: %s",
url.String())
+ }
+ return
+}
+
+// isProvider shows whether this url represents the application received the
request as server
+func isProvider(url *common.URL) bool {
+ role := url.GetParam(constant.RegistryRoleKey, "")
+ return strings.EqualFold(role, strconv.Itoa(common.PROVIDER))
+}
+
+// isConsumer shows whether this url represents the application sent then
request as client
+func isConsumer(url *common.URL) bool {
+ role := url.GetParam(constant.RegistryRoleKey, "")
+ return strings.EqualFold(role, strconv.Itoa(common.CONSUMER))
+}