Skip to content

Commit

Permalink
spiderpool metrics pkg optimization
Browse files Browse the repository at this point in the history
Signed-off-by: Icarus9913 <icaruswu66@qq.com>
  • Loading branch information
Icarus9913 committed Apr 23, 2022
1 parent e6558e2 commit 3a7b9ad
Show file tree
Hide file tree
Showing 54 changed files with 1,887 additions and 2,180 deletions.
22 changes: 19 additions & 3 deletions go.mod
Expand Up @@ -7,6 +7,10 @@ require (
github.com/onsi/ginkgo/v2 v2.1.3
github.com/onsi/gomega v1.19.0
github.com/sasha-s/go-deadlock v0.3.1
go.opentelemetry.io/otel v1.6.3
go.opentelemetry.io/otel/exporters/prometheus v0.29.0
go.opentelemetry.io/otel/metric v0.29.0
go.opentelemetry.io/otel/sdk/metric v0.29.0
go.uber.org/zap v1.19.0
golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff
gopkg.in/natefinch/lumberjack.v2 v2.0.0
Expand All @@ -17,15 +21,19 @@ require (
require (
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
github.com/fatih/color v1.12.0 // indirect
github.com/go-logr/logr v1.2.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/gobuffalo/flect v0.2.3 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
Expand All @@ -34,18 +42,26 @@ require (
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/spf13/cobra v1.2.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.opentelemetry.io/otel/sdk v1.6.3 // indirect
go.opentelemetry.io/otel/trace v1.6.3 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
Expand Down
30 changes: 12 additions & 18 deletions go.sum
Expand Up @@ -68,7 +68,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
Expand Down Expand Up @@ -499,30 +498,25 @@ go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUz
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk=
go.opentelemetry.io/otel v1.6.0 h1:YV6GkGe/Ag2PKsm4rjlqdSNs0w0A5ZzxeGkxhx1T+t4=
go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ=
go.opentelemetry.io/otel v1.6.3 h1:FLOfo8f9JzFVFVyU+MSRJc2HdEAXQgm7pIv2uFKRSZE=
go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI=
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
go.opentelemetry.io/otel/exporters/prometheus v0.27.0 h1:HcGi6HmYRuszR3stcvN2GctJjQtvp44nw/VdfJCo/Ec=
go.opentelemetry.io/otel/exporters/prometheus v0.27.0/go.mod h1:u0vTzijx2B6gGDa8FuIVoESW6z0HdKkXZWZMSTsoJKs=
go.opentelemetry.io/otel/internal/metric v0.27.0 h1:9dAVGAfFiiEq5NVB9FUJ5et+btbDQAUIJehJ+ikyryk=
go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/onvKapPGv7y/rpyOTI+LFNzw=
go.opentelemetry.io/otel/exporters/prometheus v0.29.0 h1:jOrFr8pCPj52GCPNq3qd69SEug3QmqDJTzbrefUxkpw=
go.opentelemetry.io/otel/exporters/prometheus v0.29.0/go.mod h1:Er2VVJQZbHysogooLNchdZ3MLYoI7+d15mHmrRlRJCU=
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
go.opentelemetry.io/otel/metric v0.27.0 h1:HhJPsGhJoKRSegPQILFbODU56NS/L1UE4fS1sC5kIwQ=
go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g=
go.opentelemetry.io/otel/metric v0.29.0 h1:7unM/I13Dbc1VHw8lTPQ7zfNIgkhcb8BZhujXOS4jKc=
go.opentelemetry.io/otel/metric v0.29.0/go.mod h1:HahKFp1OC1RNTsuO/HNMBHHJR+dmHZ7wLARRgGDwjLQ=
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
go.opentelemetry.io/otel/sdk v1.4.0/go.mod h1:71GJPNJh4Qju6zJuYl1CrYtXbrgfau/M9UAggqiy1UE=
go.opentelemetry.io/otel/sdk v1.6.0 h1:JoriAoiNENuxxIQApR1O0k2h1Md5QegZhbentcRJpWk=
go.opentelemetry.io/otel/sdk v1.6.0/go.mod h1:PjLRUfDsoPy0zl7yrDGSUqjj43tL7rEtFdCEiGlxXRM=
go.opentelemetry.io/otel/sdk v1.6.3 h1:prSHYdwCQOX5DrsEzxowH3nLhoAzEBdZhvrR79scfLs=
go.opentelemetry.io/otel/sdk v1.6.3/go.mod h1:A4iWF7HTXa+GWL/AaqESz28VuSBIcZ+0CV+IzJ5NMiQ=
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
go.opentelemetry.io/otel/sdk/metric v0.27.0 h1:CDEu96Js5IP7f4bJ8eimxF09V5hKYmE7CeyKSjmAL1s=
go.opentelemetry.io/otel/sdk/metric v0.27.0/go.mod h1:lOgrT5C3ORdbqp2LsDrx+pBj6gbZtQ5Omk27vH3EaW0=
go.opentelemetry.io/otel/sdk/metric v0.29.0 h1:OCEp2igPFXQrGxSR/nwd/bDjkPlPlOVjIULA/ob0dNw=
go.opentelemetry.io/otel/sdk/metric v0.29.0/go.mod h1:IFkFNKI8Gq8zBdqOKdODCL9+LInBZLXaGpqSIKphNuU=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE=
go.opentelemetry.io/otel/trace v1.6.0 h1:NDzPermp9ISkhxIaJXjBTi2O60xOSHDHP/EezjOL2wo=
go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE=
go.opentelemetry.io/otel/trace v1.6.3 h1:IqN4L+5b0mPNjdXIiZ90Ni4Bl5BRkDQywePLWemd9bc=
go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
Expand Down
27 changes: 15 additions & 12 deletions pkg/metrics/metrics.go
Expand Up @@ -11,6 +11,9 @@ import (
"go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/global"
"go.opentelemetry.io/otel/metric/instrument"
"go.opentelemetry.io/otel/metric/instrument/syncfloat64"
"go.opentelemetry.io/otel/metric/instrument/syncint64"
"go.opentelemetry.io/otel/sdk/metric/aggregator/histogram"
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
"go.opentelemetry.io/otel/sdk/metric/export/aggregation"
Expand All @@ -23,7 +26,7 @@ var meter metric.Meter

// InitMetricController will set up meter with the input param(required) and create a prometheus exporter.
// returns http handler and error
func InitMetricController(meterName string) (func(w http.ResponseWriter, r *http.Request), error) {
func InitMetricController(meterName string) (http.Handler, error) {
if len(meterName) == 0 {
return nil, fmt.Errorf("Failed to init metric controller, meter name is asked to be set!")
}
Expand All @@ -48,25 +51,25 @@ func InitMetricController(meterName string) (func(w http.ResponseWriter, r *http
m := global.Meter(meterName)
meter = m

return exporter.ServeHTTP, nil
return exporter, nil
}

// NewMetricInt64Counter will create otel Int64Counter metric. The first param metricName is required and
// the second param is optional.
func NewMetricInt64Counter(metricName string, description string) (metric.Int64Counter, error) {
// NewMetricInt64Counter will create otel Int64Counter metric.
// The first param metricName is required and the second param is optional.
func NewMetricInt64Counter(metricName string, description string) (syncint64.Counter, error) {
if len(metricName) == 0 {
return metric.Int64Counter{}, fmt.Errorf("Failed to create metric Int64Counter, metric name is asked to be set.")
return nil, fmt.Errorf("Failed to create metric Int64Counter, metric name is asked to be set.")
}
return metric.Must(meter).NewInt64Counter(metricName, metric.WithDescription(description)), nil
return meter.SyncInt64().Counter(metricName, instrument.WithDescription(description))
}

// NewMetricFloat64Histogram will create otel Float64Histogram metric. The first param metricName is required and
// the second param is optional.
func NewMetricFloat64Histogram(metricName string, description string) (metric.Float64Histogram, error) {
// NewMetricFloat64Histogram will create otel Float64Histogram metric.
// The first param metricName is required and the second param is optional.
func NewMetricFloat64Histogram(metricName string, description string) (syncfloat64.Histogram, error) {
if len(metricName) == 0 {
return metric.Float64Histogram{}, fmt.Errorf("Failed to create metric Float64Histogram, metric name is asked to be set.")
return nil, fmt.Errorf("Failed to create metric Float64Histogram, metric name is asked to be set.")
}
return metric.Must(meter).NewFloat64Histogram(metricName, metric.WithDescription(description)), nil
return meter.SyncFloat64().Histogram(metricName, instrument.WithDescription(description))
}

var _ TimeRecorder = &timeRecorder{}
Expand Down
52 changes: 52 additions & 0 deletions pkg/metrics/metrics_suite_test.go
Expand Up @@ -4,13 +4,65 @@
package metrics_test

import (
"context"
"net"
"net/http"
"testing"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/spidernet-io/spiderpool/pkg/metrics"
)

var (
listener net.Listener
server *http.Server
httpHandle http.Handler
err error
ctx context.Context
)

func TestMetrics(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Metrics Suite")
}

// start a http server to set up an otel exporter
var _ = BeforeSuite(func() {
ctx = context.TODO()

server = new(http.Server)
httpHandle, err = metrics.InitMetricController(SpiderPoolMeter)
Expect(err).NotTo(HaveOccurred())

go func() {
defer GinkgoRecover()

/* Obtain a reference to a local port for the given sock,
* if snum is zero it means select any available local port.
*/
listener, err = net.Listen("tcp", net.JoinHostPort("0.0.0.0", "0"))
Expect(err).NotTo(HaveOccurred())

MetricsTestServerAddr = "http://" + listener.Addr().String()

server.Handler = httpHandle
server.IdleTimeout = time.Second * 10
server.ReadTimeout = time.Second * 30
server.WriteTimeout = time.Second * 60

err = server.Serve(listener)
if nil != err && err != http.ErrServerClosed {
By("Error: Otel metrics http server failed. " + err.Error())
}

}()
})

// close http listener
var _ = AfterSuite(func() {
err = server.Shutdown(ctx)
Expect(err).NotTo(HaveOccurred())
})
125 changes: 93 additions & 32 deletions pkg/metrics/metrics_test.go
Expand Up @@ -4,18 +4,31 @@
package metrics_test

import (
"bufio"
"context"
"io"
"net/http"
"strconv"
"strings"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/spidernet-io/spiderpool/pkg/metrics"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/instrument/syncfloat64"
"go.opentelemetry.io/otel/metric/instrument/syncint64"
)

const (
OTEL_COUNTS_SIGNAL = "ippool=\"default_pool\""
)

var (
verifyCount int

MetricsTestServerAddr = ""
SpiderPoolMeter = "spider_pool_meter"
MetricNodeIPAllocationCountsName = "Node_IP_Allocation_Counts"
MetricNodeIPAllocationDurationName = "Node_IP_Allocation_Duration"
Expand All @@ -25,24 +38,11 @@ type IPAllocation struct {
NodeName string
PoolName string
// ....
MetricNodeIPAllocationCounts metric.Int64Counter
MetricNodeIPAllocationDuration metric.Float64Histogram
MetricNodeIPAllocationCounts syncint64.Counter
MetricNodeIPAllocationDuration syncfloat64.Histogram
}

var _ = Describe("check otel with prometheus", Ordered, func() {
var httpHandle func(http.ResponseWriter, *http.Request)
var err error

BeforeAll(func() {
httpHandle, err = metrics.InitMetricController(SpiderPoolMeter)
Expect(err).NotTo(HaveOccurred())

http.HandleFunc("/metrics", httpHandle)
go func() {
_ = http.ListenAndServe(":2222", nil)
}()
})

var _ = Describe("metrics", Label("unitest", "metrics_test"), Ordered, func() {
It("use prometheus as exporter", func() {
c := make(chan bool)
ctx := context.Background()
Expand All @@ -60,25 +60,86 @@ var _ = Describe("check otel with prometheus", Ordered, func() {
Expect(err).NotTo(HaveOccurred())
ipAllocation.MetricNodeIPAllocationDuration = histogram

// ip allocation logics....
timeRecorder := metrics.NewTimeRecorder()
// ....
// verifyRecord willverify whether the metrics record correctly
verifyRecord := func(duration float64) {
resp, err := http.Get(MetricsTestServerAddr)
Expect(err).NotTo(HaveOccurred())
defer func(Body io.ReadCloser) {
err = Body.Close()
Expect(err).NotTo(HaveOccurred())
}(resp.Body)

reader := bufio.NewReader(resp.Body)

for {
line, err := reader.ReadString('\n')
if nil != err || io.EOF == err {
if line == "" {
break
}
}

// verify counts instrument
if strings.Contains(line, MetricNodeIPAllocationCountsName) && strings.Contains(line, OTEL_COUNTS_SIGNAL) {
split := strings.Split(line, " ")
Expect(err).NotTo(HaveOccurred())
Expect(split[len(split)-1]).Should(Equal("2\n"))
verifyCount++
}

// verify histogram instrument
if strings.Contains(line, MetricNodeIPAllocationDurationName+"_sum") {
split := strings.Split(line, " ")
Expect(err).NotTo(HaveOccurred())
Expect(split[len(split)-1]).Should(Equal(strconv.FormatFloat(duration, 'f', -1, 64) + "\n"))
verifyCount++
}
}
Expect(verifyCount).Should(Equal(2))
}

// metrics record data
go func() {
defer GinkgoRecover()

// ip allocation logics....
timeRecorder := metrics.NewTimeRecorder()
// ....

// ip allocation succeed
// record the counter metric without labels.
ipAllocation.MetricNodeIPAllocationCounts.Add(ctx, 1)
// ip allocation succeed
// record the counter metric without labels.
ipAllocation.MetricNodeIPAllocationCounts.Add(ctx, 1, attribute.Key("ippool").String("default_pool"))

time.Sleep(time.Second * 10)
ipAllocation.MetricNodeIPAllocationCounts.Add(ctx, 1)
time.Sleep(time.Second * 5)
ipAllocation.MetricNodeIPAllocationCounts.Add(ctx, 1, attribute.Key("ippool").String("default_pool"))

// record histogram metric with labels.
duration := timeRecorder.SinceInSeconds()
ipAllocation.MetricNodeIPAllocationDuration.Record(ctx, duration,
attribute.Key("hostname").String("node1"),
attribute.Key("type").String("total"))
// record histogram metric with labels.
duration := timeRecorder.SinceInSeconds()
ipAllocation.MetricNodeIPAllocationDuration.Record(ctx, duration,
attribute.Key("hostname").String("node1"),
attribute.Key("type").String("total"))

time.Sleep(time.Second * 1)
verifyRecord(duration)

close(c)
}()

close(c)
//Consistently(c, "60s").Should(BeClosed())
Eventually(c, "20s").Should(BeClosed())
})

It("test empty counter metric name", func() {
_, err := metrics.NewMetricInt64Counter("", "")
Expect(err).To(HaveOccurred())
})

It("test empty histogram metric name", func() {
_, err := metrics.NewMetricFloat64Histogram("", "")
Expect(err).To(HaveOccurred())
})

It("test InitMetricController with empty meter name", func() {
_, err := metrics.InitMetricController("")
Expect(err).To(HaveOccurred())
})
})

0 comments on commit 3a7b9ad

Please sign in to comment.