From f6fdbfdf772ad7f82ea64b8d861e4140c3fa17cb Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Tue, 4 Jul 2023 13:34:20 +0800 Subject: [PATCH] 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(-) delete mode 100644 metrics/prometheus/after_invocation.go delete mode 100644 metrics/prometheus/before_invocation.go rename metrics/prometheus/{common.go => model.go} (57%) create mode 100644 metrics/prometheus/util.go diff --git a/metrics/prometheus/after_invocation.go b/metrics/prometheus/after_invocation.go deleted file mode 100644 index f1235a2d75..0000000000 --- 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 7477b13626..0000000000 --- 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 95e090d466..35858853f4 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 79c0203690..115c6ca3db 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 32137d1e2a..d62734f8fc 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 8c38c6114e..7ca4398bf5 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 0000000000..4e1a9c8dc6 --- /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)) +}