Skip to content
Snippets Groups Projects
Commit 2d665520 authored by flycash's avatar flycash
Browse files

Support histogram

parent 10d0ac89
No related branches found
No related tags found
No related merge requests found
......@@ -17,9 +17,14 @@
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"`
Reporters []string `yaml:"reporters" json:"reporters,omitempty"`
HistogramBucket []float64 `yaml:"histogram_bucket" json:"histogram_bucket,omitempty"`
}
// find the MetricConfig
......@@ -30,3 +35,12 @@ func GetMetricConfig() *MetricConfig {
}
return metricConfig
}
// 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
}
......@@ -32,6 +32,7 @@ import (
"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"
)
......@@ -48,15 +49,28 @@ const (
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, remoteKey, localKey}
)
// should initialize after loading configuration
func init() {
rpt := &PrometheusReporter{
consumerVec: newSummaryVec(consumerKey),
providerVec: newSummaryVec(providerKey),
consumerSummaryVec: newSummaryVec(consumerKey),
providerSummaryVec: newSummaryVec(providerKey),
consumerHistogramVec: newHistogramVec(consumerKey),
providerHistogramVec: newHistogramVec(providerKey),
}
prometheus.MustRegister(rpt.consumerVec, rpt.providerVec)
prometheus.MustRegister(rpt.consumerSummaryVec, rpt.providerSummaryVec,
rpt.consumerHistogramVec, rpt.providerHistogramVec)
extension.SetMetricReporter(reporterName, rpt)
}
......@@ -65,27 +79,35 @@ func init() {
// https://prometheus.io/docs/guides/go-application/
type PrometheusReporter struct {
// report the consumer-side's data
consumerVec *prometheus.SummaryVec
// report the provider-side's data
providerVec *prometheus.SummaryVec
// 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 the duration to Prometheus
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.providerVec
sumVec = reporter.providerSummaryVec
hisVec = reporter.providerHistogramVec
} else if isConsumer(url) {
sumVec = reporter.consumerVec
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
}
sumVec.With(prometheus.Labels{
labels := prometheus.Labels{
serviceKey: url.Service(),
groupKey: url.GetParam(groupKey, ""),
versionKey: url.GetParam(versionKey, ""),
......@@ -93,7 +115,24 @@ func (reporter *PrometheusReporter) Report(ctx context.Context, invoker protocol
timeoutKey: url.GetParam(timeoutKey, ""),
remoteKey: invocation.AttachmentsByKey(constant.REMOTE_ADDR, ""),
localKey: invocation.AttachmentsByKey(constant.REMOTE_ADDR, ""),
}).Observe(float64(cost.Nanoseconds() / constant.MsToNanoRate))
}
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: metrics.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
......@@ -115,9 +154,9 @@ func newSummaryVec(side string) *prometheus.SummaryVec {
return prometheus.NewSummaryVec(
prometheus.SummaryOpts{
Namespace: metrics.NameSpace,
Help: "this is the dubbo's metrics",
Help: "This is the dubbo's summary metrics",
Subsystem: side,
Name: serviceKey,
Name: serviceKey + summarySuffix,
Objectives: map[float64]float64{
0.5: 0.01,
0.75: 0.01,
......@@ -127,6 +166,6 @@ func newSummaryVec(side string) *prometheus.SummaryVec {
0.999: 0.0001,
},
},
[]string{serviceKey, groupKey, versionKey, methodKey, timeoutKey, remoteKey, localKey},
labelNames,
)
}
......@@ -49,4 +49,24 @@ func TestPrometheusReporter_Report(t *testing.T) {
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)
}
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