Skip to content
Snippets Groups Projects
Unverified Commit 0074a015 authored by Ming Deng's avatar Ming Deng Committed by GitHub
Browse files

Merge pull request #342 from flycash/feature/prometheus

Ftr: Prometheus Support —— Summary & Histogram
parents bfef9d27 31ca039c
No related branches found
No related tags found
No related merge requests found
/*
* 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 constant
import (
"time"
)
var (
MsToNanoRate = int64(time.Millisecond / time.Nanosecond)
)
/*
* 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 extension
import (
"github.com/apache/dubbo-go/metrics"
)
var (
// we couldn't store the instance because the some instance may initialize before loading configuration
// so lazy initialization will be better.
metricReporterMap = make(map[string]func() metrics.Reporter, 4)
)
// SetMetricReporter set a reporter with the name
func SetMetricReporter(name string, reporterFunc func() metrics.Reporter) {
metricReporterMap[name] = reporterFunc
}
// GetMetricReporter find the reporter with name.
// if not found, it will panic.
// we should know that this method usually is called when system starts, so we should panic
func GetMetricReporter(name string) metrics.Reporter {
reporterFunc, found := metricReporterMap[name]
if !found {
panic("Cannot find the reporter with name: " + name)
}
return reporterFunc()
}
/*
* 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 extension
import (
"context"
"testing"
"time"
)
import (
"github.com/stretchr/testify/assert"
)
import (
"github.com/apache/dubbo-go/metrics"
"github.com/apache/dubbo-go/protocol"
)
func TestGetMetricReporter(t *testing.T) {
reporter := &mockReporter{}
name := "mock"
SetMetricReporter(name, func() metrics.Reporter {
return reporter
})
res := GetMetricReporter(name)
assert.Equal(t, reporter, res)
}
type mockReporter struct {
}
func (m mockReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) {
}
......@@ -40,12 +40,14 @@ type multiConfiger interface {
Prefix() string
}
// BaseConfig ...
// BaseConfig is the common configuration for provider and consumer
type BaseConfig struct {
ConfigCenterConfig *ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"`
configCenterUrl *common.URL
prefix string
fatherConfig interface{}
MetricConfig *MetricConfig `yaml:"metrics" json:"metrics,omitempty"`
}
func (c *BaseConfig) startConfigCenter(ctx context.Context) error {
......
......@@ -31,9 +31,11 @@ import (
)
var (
consumerConfig *ConsumerConfig
providerConfig *ProviderConfig
maxWait = 3
consumerConfig *ConsumerConfig
providerConfig *ProviderConfig
metricConfig *MetricConfig
applicationConfig *ApplicationConfig
maxWait = 3
)
// loaded consumer & provider config from xxx.yml, and log config from xxx.xml
......@@ -75,6 +77,10 @@ func Load() {
if consumerConfig == nil {
logger.Warnf("consumerConfig is nil!")
} else {
metricConfig = consumerConfig.MetricConfig
applicationConfig = consumerConfig.ApplicationConfig
checkApplicationName(consumerConfig.ApplicationConfig)
if err := configCenterRefreshConsumer(); err != nil {
logger.Errorf("[consumer config center refresh] %#v", err)
......@@ -131,6 +137,11 @@ func Load() {
if providerConfig == nil {
logger.Warnf("providerConfig is nil!")
} else {
// so, you should know that the consumer's config will be override
metricConfig = providerConfig.MetricConfig
applicationConfig = providerConfig.ApplicationConfig
checkApplicationName(providerConfig.ApplicationConfig)
if err := configCenterRefreshProvider(); err != nil {
logger.Errorf("[provider config center refresh] %#v", err)
......@@ -162,3 +173,42 @@ func GetRPCService(name string) common.RPCService {
func RPCService(service common.RPCService) {
consumerConfig.References[service.Reference()].Implement(service)
}
// GetMetricConfig find the MetricConfig
// if it is nil, create a new one
func GetMetricConfig() *MetricConfig {
if metricConfig == nil {
metricConfig = &MetricConfig{}
}
return metricConfig
}
// GetApplicationConfig find the application config
// if not, we will create one
// Usually applicationConfig will be initialized when system start
func GetApplicationConfig() *ApplicationConfig {
if applicationConfig == nil {
applicationConfig = &ApplicationConfig{}
}
return applicationConfig
}
// GetProviderConfig find the provider config
// if not found, create new one
func GetProviderConfig() ProviderConfig {
if providerConfig == nil {
logger.Warnf("providerConfig is nil!")
return ProviderConfig{}
}
return *providerConfig
}
// GetConsumerConfig find the consumer config
// if not found, create new one
func GetConsumerConfig() ConsumerConfig {
if consumerConfig == nil {
logger.Warnf("consumerConfig is nil!")
return ConsumerConfig{}
}
return *consumerConfig
}
......@@ -85,15 +85,6 @@ func SetConsumerConfig(c ConsumerConfig) {
consumerConfig = &c
}
// GetConsumerConfig ...
func GetConsumerConfig() ConsumerConfig {
if consumerConfig == nil {
logger.Warnf("consumerConfig is nil!")
return ConsumerConfig{}
}
return *consumerConfig
}
// ConsumerInit ...
func ConsumerInit(confConFile string) error {
if confConFile == "" {
......
/*
* 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 config
var (
defaultHistogramBucket = []float64{10, 50, 100, 200, 500, 1000, 10000}
)
// This is the config struct for all metrics implementation
type MetricConfig struct {
Reporters []string `yaml:"reporters" json:"reporters,omitempty"`
HistogramBucket []float64 `yaml:"histogram_bucket" json:"histogram_bucket,omitempty"`
}
// find the histogram bucket
// if it's empty, the default value will be return
func (mc *MetricConfig) GetHistogramBucket() []float64 {
if len(mc.HistogramBucket) == 0 {
mc.HistogramBucket = defaultHistogramBucket
}
return mc.HistogramBucket
}
/*
* 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 config
import (
"testing"
)
import (
"github.com/stretchr/testify/assert"
)
func TestGetMetricConfig(t *testing.T) {
empty := GetMetricConfig()
assert.NotNil(t, empty)
}
......@@ -76,15 +76,6 @@ func SetProviderConfig(p ProviderConfig) {
providerConfig = &p
}
// GetProviderConfig ...
func GetProviderConfig() ProviderConfig {
if providerConfig == nil {
logger.Warnf("providerConfig is nil!")
return ProviderConfig{}
}
return *providerConfig
}
// ProviderInit ...
func ProviderInit(confProFile string) error {
if len(confProFile) == 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 filter_impl
import (
"context"
"time"
)
import (
"github.com/apache/dubbo-go/common/extension"
"github.com/apache/dubbo-go/config"
"github.com/apache/dubbo-go/filter"
"github.com/apache/dubbo-go/metrics"
"github.com/apache/dubbo-go/protocol"
)
const (
metricFilterName = "metrics"
)
var (
metricFilterInstance filter.Filter
)
// must initialized before using the filter and after loading configuration
func init() {
extension.SetFilter(metricFilterName, newMetricsFilter)
}
// metricFilter will calculate the invocation's duration and the report to the reporters
// If you want to use this filter to collect the metrics,
// Adding this into your configuration file, like:
// filter: "metrics"
// metrics:
// reporter:
// - "your reporter" # here you should specify the reporter, for example 'prometheus'
// more info please take a look at dubbo-samples projects
type metricsFilter struct {
reporters []metrics.Reporter
}
// Invoke collect the duration of invocation and then report the duration by using goroutine
func (p *metricsFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
start := time.Now()
res := invoker.Invoke(ctx, invocation)
end := time.Now()
duration := end.Sub(start)
go func() {
for _, reporter := range p.reporters {
reporter.Report(ctx, invoker, invocation, duration, res)
}
}()
return res
}
// OnResponse do nothing and return the result
func (p *metricsFilter) OnResponse(ctx context.Context, res protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
return res
}
// newMetricsFilter the metricsFilter is singleton.
// it's lazy initialization
// make sure that the configuration had been loaded before invoking this method.
func newMetricsFilter() filter.Filter {
if metricFilterInstance == nil {
reporterNames := config.GetMetricConfig().Reporters
reporters := make([]metrics.Reporter, 0, len(reporterNames))
for _, name := range reporterNames {
reporters = append(reporters, extension.GetMetricReporter(name))
}
metricFilterInstance = &metricsFilter{
reporters: reporters,
}
}
return metricFilterInstance
}
/*
* 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 filter_impl
import (
"context"
"sync"
"testing"
"time"
)
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
import (
"github.com/apache/dubbo-go/common"
"github.com/apache/dubbo-go/common/extension"
"github.com/apache/dubbo-go/config"
"github.com/apache/dubbo-go/metrics"
"github.com/apache/dubbo-go/protocol"
"github.com/apache/dubbo-go/protocol/invocation"
)
func TestMetricsFilter_Invoke(t *testing.T) {
// prepare the mock reporter
config.GetMetricConfig().Reporters = []string{"mock"}
mk := &mockReporter{}
extension.SetMetricReporter("mock", func() metrics.Reporter {
return mk
})
instance := extension.GetFilter(metricFilterName)
url, _ := common.NewURL(context.Background(),
"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+
"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+
"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+
"BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&"+
"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
invoker := protocol.NewBaseInvoker(url)
attach := make(map[string]string, 10)
inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
ctx := context.Background()
mk.On("Report", ctx, invoker, inv).Return(true, nil)
mk.wg.Add(1)
result := instance.Invoke(ctx, invoker, inv)
assert.NotNil(t, result)
mk.AssertNotCalled(t, "Report", 1)
// it will do nothing
result = instance.OnResponse(ctx, nil, invoker, inv)
assert.Nil(t, result)
}
type mockReporter struct {
mock.Mock
wg sync.WaitGroup
}
func (m *mockReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) {
m.Called(ctx, invoker, invocation)
m.wg.Done()
}
......@@ -38,7 +38,7 @@ require (
github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb
github.com/opentracing/opentracing-go v1.1.0
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v1.1.0 // indirect
github.com/prometheus/client_golang v1.1.0
github.com/satori/go.uuid v1.2.0
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect
github.com/soheilhy/cmux v0.1.4 // indirect
......
/*
* 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"
"strconv"
"strings"
"sync"
"time"
)
import (
"github.com/prometheus/client_golang/prometheus"
)
import (
"github.com/apache/dubbo-go/common"
"github.com/apache/dubbo-go/common/constant"
"github.com/apache/dubbo-go/common/extension"
"github.com/apache/dubbo-go/common/logger"
"github.com/apache/dubbo-go/config"
"github.com/apache/dubbo-go/metrics"
"github.com/apache/dubbo-go/protocol"
)
const (
reporterName = "prometheus"
serviceKey = constant.SERVICE_KEY
groupKey = constant.GROUP_KEY
versionKey = constant.VERSION_KEY
methodKey = constant.METHOD_KEY
timeoutKey = constant.TIMEOUT_KEY
providerKey = "provider"
consumerKey = "consumer"
// to identify the metric's type
histogramSuffix = "_histogram"
// to identify the metric's type
summarySuffix = "_summary"
)
var (
labelNames = []string{serviceKey, groupKey, versionKey, methodKey, timeoutKey}
namespace = config.GetApplicationConfig().Name
reporterInstance *PrometheusReporter
reporterInitOnce sync.Once
)
// should initialize after loading configuration
func init() {
extension.SetMetricReporter(reporterName, newPrometheusReporter)
}
// PrometheusReporter
// it will collect the data for Prometheus
// if you want to use this, you should initialize your prometheus.
// https://prometheus.io/docs/guides/go-application/
type PrometheusReporter struct {
// report the consumer-side's summary data
consumerSummaryVec *prometheus.SummaryVec
// report the provider-side's summary data
providerSummaryVec *prometheus.SummaryVec
// report the provider-side's histogram data
providerHistogramVec *prometheus.HistogramVec
// report the consumer-side's histogram data
consumerHistogramVec *prometheus.HistogramVec
}
// Report report the duration to Prometheus
// the role in url must be consumer or provider
// or it will be ignored
func (reporter *PrometheusReporter) Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation, cost time.Duration, res protocol.Result) {
url := invoker.GetUrl()
var sumVec *prometheus.SummaryVec
var hisVec *prometheus.HistogramVec
if isProvider(url) {
sumVec = reporter.providerSummaryVec
hisVec = reporter.providerHistogramVec
} else if isConsumer(url) {
sumVec = reporter.consumerSummaryVec
hisVec = reporter.consumerHistogramVec
} else {
logger.Warnf("The url is not the consumer's or provider's, "+
"so the invocation will be ignored. url: %s", url.String())
return
}
labels := prometheus.Labels{
serviceKey: url.Service(),
groupKey: url.GetParam(groupKey, ""),
versionKey: url.GetParam(versionKey, ""),
methodKey: invocation.MethodName(),
timeoutKey: url.GetParam(timeoutKey, ""),
}
costMs := float64(cost.Nanoseconds() / constant.MsToNanoRate)
sumVec.With(labels).Observe(costMs)
hisVec.With(labels).Observe(costMs)
}
func newHistogramVec(side string) *prometheus.HistogramVec {
mc := config.GetMetricConfig()
return prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: namespace,
Subsystem: side,
Name: serviceKey + histogramSuffix,
Help: "This is the dubbo's histogram metrics",
Buckets: mc.GetHistogramBucket(),
},
labelNames)
}
// whether this url represents the application received the request as server
func isProvider(url common.URL) bool {
role := url.GetParam(constant.ROLE_KEY, "")
return strings.EqualFold(role, strconv.Itoa(common.PROVIDER))
}
// whether this url represents the application sent then request as client
func isConsumer(url common.URL) bool {
role := url.GetParam(constant.ROLE_KEY, "")
return strings.EqualFold(role, strconv.Itoa(common.CONSUMER))
}
// newSummaryVec create SummaryVec, the Namespace is dubbo
// the objectives is from my experience.
func newSummaryVec(side string) *prometheus.SummaryVec {
return prometheus.NewSummaryVec(
prometheus.SummaryOpts{
Namespace: namespace,
Help: "This is the dubbo's summary metrics",
Subsystem: side,
Name: serviceKey + summarySuffix,
Objectives: map[float64]float64{
0.5: 0.01,
0.75: 0.01,
0.90: 0.005,
0.98: 0.002,
0.99: 0.001,
0.999: 0.0001,
},
},
labelNames,
)
}
// newPrometheusReporter create new prometheusReporter
// it will register the metrics into prometheus
func newPrometheusReporter() metrics.Reporter {
if reporterInstance == nil {
reporterInitOnce.Do(func() {
reporterInstance = &PrometheusReporter{
consumerSummaryVec: newSummaryVec(consumerKey),
providerSummaryVec: newSummaryVec(providerKey),
consumerHistogramVec: newHistogramVec(consumerKey),
providerHistogramVec: newHistogramVec(providerKey),
}
prometheus.MustRegister(reporterInstance.consumerSummaryVec, reporterInstance.providerSummaryVec,
reporterInstance.consumerHistogramVec, reporterInstance.providerHistogramVec)
})
}
return reporterInstance
}
/*
* 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"
"testing"
"time"
)
import (
"github.com/stretchr/testify/assert"
)
import (
"github.com/apache/dubbo-go/common"
"github.com/apache/dubbo-go/common/extension"
"github.com/apache/dubbo-go/protocol"
"github.com/apache/dubbo-go/protocol/invocation"
)
func TestPrometheusReporter_Report(t *testing.T) {
reporter := extension.GetMetricReporter(reporterName)
url, _ := common.NewURL(context.Background(),
"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+
"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+
"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+
"BDTService&organization=ikurento.com&owner=ZX&registry.role=3&retries=&"+
"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
invoker := protocol.NewBaseInvoker(url)
attach := make(map[string]string, 10)
inv := invocation.NewRPCInvocation("MethodName", []interface{}{"OK", "Hello"}, attach)
assert.False(t, isConsumer(url))
ctx := context.Background()
reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil)
// consumer side
url, _ = common.NewURL(context.Background(),
"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+
"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+
"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+
"BDTService&organization=ikurento.com&owner=ZX&registry.role=0&retries=&"+
"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
invoker = protocol.NewBaseInvoker(url)
reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil)
// invalid role
url, _ = common.NewURL(context.Background(),
"dubbo://:20000/UserProvider?app.version=0.0.1&application=BDTService&bean.name=UserProvider"+
"&cluster=failover&environment=dev&group=&interface=com.ikurento.user.UserProvider&loadbalance=random&methods.GetUser."+
"loadbalance=random&methods.GetUser.retries=1&methods.GetUser.weight=0&module=dubbogo+user-info+server&name="+
"BDTService&organization=ikurento.com&owner=ZX&registry.role=9&retries=&"+
"service.filter=echo%2Ctoken%2Caccesslog&timestamp=1569153406&token=934804bf-b007-4174-94eb-96e3e1d60cc7&version=&warmup=100")
invoker = protocol.NewBaseInvoker(url)
reporter.Report(ctx, invoker, inv, 100*time.Millisecond, nil)
}
/*
* 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 metrics
import (
"context"
"time"
)
import (
"github.com/apache/dubbo-go/protocol"
)
const (
NameSpace = "dubbo"
)
// it will be use to report the invocation's duration
type Reporter interface {
// report the duration of an invocation
Report(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation,
cost time.Duration, res protocol.Result)
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment