From 505d10b0c120675999a3716db09e88a522d6512c Mon Sep 17 00:00:00 2001 From: yeya24 Date: Fri, 19 Jul 2019 21:10:32 +0800 Subject: [PATCH] add how to add metrics and refact metrics to package common Signed-off-by: yeya24 --- common/util/metrics_util.go | 64 +++++++++++++++++++++++++++++++++++ docs/user_guide/monitoring.md | 20 ++++++++++- supernode/config/constants.go | 8 ++--- supernode/server/metrics.go | 52 +++++++--------------------- test/util_api.go | 6 +++- version/version.go | 17 +++------- 6 files changed, 109 insertions(+), 58 deletions(-) create mode 100644 common/util/metrics_util.go diff --git a/common/util/metrics_util.go b/common/util/metrics_util.go new file mode 100644 index 000000000..a1eba76e0 --- /dev/null +++ b/common/util/metrics_util.go @@ -0,0 +1,64 @@ +package util + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +const ( + namespace = "dragonfly" +) + +// NewCounter will auto-register a Counter metric to prometheus default registry and return it. +func NewCounter(subsystem, name, help string, labels []string) *prometheus.CounterVec { + return promauto.NewCounterVec( + prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: name, + Help: help, + }, + labels, + ) +} + +// NewGauge will auto-register a Gauge metric to prometheus default registry and return it. +func NewGauge(subsystem, name, help string, labels []string) *prometheus.GaugeVec { + return promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: name, + Help: help, + }, + labels, + ) +} + +// NewSummary will auto-register a Summary metric to prometheus default registry and return it. +func NewSummary(subsystem, name, help string, labels []string, objectives map[float64]float64) *prometheus.SummaryVec { + return promauto.NewSummaryVec( + prometheus.SummaryOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: name, + Help: help, + Objectives: objectives, + }, + labels, + ) +} + +// NewHistogram will auto-register a Histogram metric to prometheus default registry and return it. +func NewHistogram(subsystem, name, help string, labels []string, buckets []float64) *prometheus.HistogramVec { + return promauto.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: name, + Help: help, + Buckets: buckets, + }, + labels, + ) +} diff --git a/docs/user_guide/monitoring.md b/docs/user_guide/monitoring.md index c3893dc82..702bd62a4 100644 --- a/docs/user_guide/monitoring.md +++ b/docs/user_guide/monitoring.md @@ -111,4 +111,22 @@ Finally you can start Prometheus in the same directory. If Prometheus works well In Prometheus web ui, you can search Dragonfly metrics below. If you want to learn more about Prometheus query language, please check [promql](https://prometheus.io/docs/prometheus/latest/querying/basics/) for help. -![dragonfly_metrics.png](../images/dragonfly_metrics.png) \ No newline at end of file +![dragonfly_metrics.png](../images/dragonfly_metrics.png) + +### Add your own metrics + +Sometimes maybe you want to add your own metrics to Dragonfly. First please ensure you know the basic concepts about Prometheus metrics. If you don't, please check [metrics types](https://prometheus.io/docs/concepts/metric_types/). + +We provide several functions to add metrics easily. Here is an example to add a Counter type metric. + +``` go +import "github.com/dragonflyoss/Dragonfly/common/util" + +requestCounter := util.NewCounter("supernode", "http_requests_total", + "Counter of HTTP requests.", []string{"code"}) +requestCounter.WithLabelValues("200").Inc() +``` + +This function will auto-register metrics to Prometheus default registry and you can get `dragonfly_supernode_http_requests_total{code,handler,method}` in /metrics endpoint. Here we also add prefix `dragonfly` to metrics name by default. If you want to learn more about how to use these metrics after getting them, please check [prometheus/client_golang](https://github.com/prometheus/client_golang). + +As for naming of metric and label, it is better to follow the best practice. We suggest you to check this [metric and label naming](https://prometheus.io/docs/practices/naming/) guide for more detailed information. \ No newline at end of file diff --git a/supernode/config/constants.go b/supernode/config/constants.go index 781ca6a56..2b7f4ad09 100644 --- a/supernode/config/constants.go +++ b/supernode/config/constants.go @@ -70,8 +70,8 @@ const ( ) const ( - // Namespace is the prefix of the metrics' name of dragonfly - Namespace = "dragonfly" - // Subsystem represents metrics for supernode - Subsystem = "supernode" + // SubsystemSupernode represents metrics from supernode + SubsystemSupernode = "supernode" + // SubsystemDfget represents metrics from dfget + SubsystemDfget = "dfget" ) diff --git a/supernode/server/metrics.go b/supernode/server/metrics.go index a5dcbdb50..d4dbd054b 100644 --- a/supernode/server/metrics.go +++ b/supernode/server/metrics.go @@ -3,10 +3,10 @@ package server import ( "net/http" + "github.com/dragonflyoss/Dragonfly/common/util" "github.com/dragonflyoss/Dragonfly/supernode/config" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" ) @@ -19,49 +19,23 @@ type metrics struct { } func newMetrics() *metrics { - m := &metrics{ - requestCounter: promauto.NewCounterVec( - prometheus.CounterOpts{ - Namespace: config.Namespace, - Subsystem: config.Subsystem, - Name: "http_requests_total", - Help: "Counter of HTTP requests.", - }, - []string{"code", "handler", "method"}, + return &metrics{ + requestCounter: util.NewCounter(config.SubsystemSupernode, "http_requests_total", + "Counter of HTTP requests.", []string{"code", "handler", "method"}, ), - requestDuration: promauto.NewHistogramVec( - prometheus.HistogramOpts{ - Namespace: config.Namespace, - Subsystem: config.Subsystem, - Name: "http_request_duration_seconds", - Help: "Histogram of latencies for HTTP requests.", - Buckets: []float64{.1, .2, .4, 1, 3, 8, 20, 60, 120}, - }, - []string{"code", "handler", "method"}, + requestDuration: util.NewHistogram(config.SubsystemSupernode, "http_request_duration_seconds", + "Histogram of latencies for HTTP requests.", []string{"code", "handler", "method"}, + []float64{.1, .2, .4, 1, 3, 8, 20, 60, 120}, ), - requestSize: promauto.NewHistogramVec( - prometheus.HistogramOpts{ - Namespace: config.Namespace, - Subsystem: config.Subsystem, - Name: "http_request_size_bytes", - Help: "Histogram of request size for HTTP requests.", - Buckets: prometheus.ExponentialBuckets(100, 10, 8), - }, - []string{"code", "handler", "method"}, + requestSize: util.NewHistogram(config.SubsystemSupernode, "http_request_size_bytes", + "Histogram of request size for HTTP requests.", []string{"code", "handler", "method"}, + prometheus.ExponentialBuckets(100, 10, 8), ), - responseSize: promauto.NewHistogramVec( - prometheus.HistogramOpts{ - Namespace: config.Namespace, - Subsystem: config.Subsystem, - Name: "http_response_size_bytes", - Help: "Histogram of response size for HTTP requests.", - Buckets: prometheus.ExponentialBuckets(100, 10, 8), - }, - []string{"code", "handler", "method"}, + responseSize: util.NewHistogram(config.SubsystemSupernode, "http_response_size_bytes", + "Histogram of response size for HTTP requests.", []string{"code", "handler", "method"}, + prometheus.ExponentialBuckets(100, 10, 8), ), } - - return m } // instrumentHandler will update metrics for every http request diff --git a/test/util_api.go b/test/util_api.go index 86e0ea6bc..ccd6a9851 100644 --- a/test/util_api.go +++ b/test/util_api.go @@ -32,7 +32,11 @@ func CheckMetric(c *check.C, metric string, value float64) { lines := strings.Split(string(data), "\n") for _, line := range lines { if strings.Contains(line, metric) { - val, err = strconv.ParseFloat(strings.Split(line, " ")[1], 64) + vals := strings.Split(line, " ") + if len(vals) != 2 { + c.Errorf("bad metrics format") + } + val, err = strconv.ParseFloat(vals[1], 64) c.Assert(err, check.IsNil) c.Assert(val, check.Equals, value) return diff --git a/version/version.go b/version/version.go index 2d0998dc2..3e0bd1997 100644 --- a/version/version.go +++ b/version/version.go @@ -27,10 +27,8 @@ import ( "strings" "text/template" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/dragonflyoss/Dragonfly/apis/types" + "github.com/dragonflyoss/Dragonfly/common/util" ) var ( @@ -109,16 +107,9 @@ func Print(program string) string { // NewBuildInfo register a collector which exports metrics about version and build information. func NewBuildInfo(program string) { - buildInfo := promauto.NewGaugeVec( - prometheus.GaugeOpts{ - Namespace: "dragonfly", - Subsystem: program, - Name: "build_info", - Help: fmt.Sprintf( - "A metric with a constant '1' value labeled by version, revision, os, arch and goversion from which %s was built.", - program, - ), - }, + buildInfo := util.NewGauge(program, "build_info", + fmt.Sprintf("A metric with a constant '1' value labeled by version, revision, os, "+ + "arch and goversion from which %s was built.", program), []string{"version", "revision", "os", "arch", "goversion"}, ) buildInfo.WithLabelValues(version, revision, os, arch, goVersion).Set(1)