diff --git a/dfdaemon/constant/constant.go b/dfdaemon/constant/constant.go index c03aa0bf2..df53a8930 100644 --- a/dfdaemon/constant/constant.go +++ b/dfdaemon/constant/constant.go @@ -46,7 +46,7 @@ const ( ) const ( - // Namespace is the prefix of the metrics' name of dragonfly + // Namespace is the prefix of metrics namespace of dragonfly Namespace = "dragonfly" // Subsystem represents metrics for dfdaemon Subsystem = "dfdaemon" diff --git a/dfdaemon/server.go b/dfdaemon/server.go index e8d6fa751..c41f43179 100644 --- a/dfdaemon/server.go +++ b/dfdaemon/server.go @@ -28,6 +28,7 @@ import ( "github.com/dragonflyoss/Dragonfly/version" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" ) @@ -83,6 +84,8 @@ func New(opts ...Option) (*Server, error) { }, proxy: p, } + // register dfdaemon build information + version.NewBuildInfo("dfdaemon", prometheus.DefaultRegisterer) for _, opt := range opts { if err := opt(s); err != nil { @@ -121,8 +124,6 @@ func (s *Server) Start() error { } else { logrus.Infof("start dfdaemon http server on %s", s.server.Addr) } - // register dfdaemon build information - version.NewBuildInfo("dfdaemon") return s.server.ListenAndServe() } diff --git a/docs/user_guide/metrics.md b/docs/user_guide/metrics.md index cfbd8a722..8c8fddbb6 100644 --- a/docs/user_guide/metrics.md +++ b/docs/user_guide/metrics.md @@ -9,6 +9,15 @@ This doc contains all the metrics that Dragonfly components currently support. N - dragonfly_supernode_http_request_duration_seconds{code, handler, method} - http request latency in seconds - dragonfly_supernode_http_request_size_bytes{code, handler, method} - http request size in bytes - dragonfly_supernode_http_response_size_bytes{code, handler, method} - http response size in bytes +- dragonfly_supernode_peers{peer} - dragonfly peers, the label peer consists of the hostname and ip address of one peer. +- dragonfly_supernode_tasks{cdnstatus} - dragonfly tasks +- dragonfly_supernode_tasks_registered_total{} - total times of registering new tasks. counter type. +- dragonfly_supernode_dfgettasks{callsystem, status} - dragonfly dfget tasks +- dragonfly_supernode_dfgettasks_registered_total{callsystem} - total times of registering new dfgettasks. counter type. +- dragonfly_supernode_dfgettasks_failed_total{callsystem} - total times of failed dfgettasks. counter type. +- dragonfly_supernode_schedule_duration_milliseconds{peer} - duration for task scheduling in milliseconds +- dragonfly_supernode_trigger_cdn_total{} - total times of triggering cdn. +- dragonfly_supernode_trigger_cdn_failed_total{} - total failed times of triggering cdn. ## Dfdaemon diff --git a/docs/user_guide/monitoring.md b/docs/user_guide/monitoring.md index 5b327ff8e..72429958d 100644 --- a/docs/user_guide/monitoring.md +++ b/docs/user_guide/monitoring.md @@ -125,7 +125,7 @@ We provide several functions to add metrics easily. Here is an example to add a import "github.com/dragonflyoss/Dragonfly/pkg/util" requestCounter := util.NewCounter("supernode", "http_requests_total", - "Counter of HTTP requests.", []string{"code"}) + "Counter of HTTP requests.", []string{"code"}, nil) requestCounter.WithLabelValues("200").Inc() ``` diff --git a/go.mod b/go.mod index 7f5675924..18dd7feb3 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( github.com/stretchr/testify v1.2.2 github.com/valyala/fasthttp v1.3.0 github.com/willf/bitset v0.0.0-20190228212526-18bd95f470f9 + golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect gopkg.in/gcfg.v1 v1.2.3 gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528 // indirect gopkg.in/warnings.v0 v0.1.2 diff --git a/go.sum b/go.sum index 405f174ed..583d2a606 100644 --- a/go.sum +++ b/go.sum @@ -182,6 +182,8 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/pkg/metricsutils/metrics_util.go b/pkg/metricsutils/metrics_util.go new file mode 100644 index 000000000..508a99b3f --- /dev/null +++ b/pkg/metricsutils/metrics_util.go @@ -0,0 +1,103 @@ +/* + * Copyright The Dragonfly Authors. + * + * Licensed 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 metricsutils + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +const ( + namespace = "dragonfly" +) + +// NewCounter will register a Counter metric to specified registry and return it. +// If registry is not specified, it will register metric to default prometheus registry. +func NewCounter(subsystem, name, help string, labels []string, register prometheus.Registerer) *prometheus.CounterVec { + if register == nil { + register = prometheus.DefaultRegisterer + } + m := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: name, + Help: help, + }, + labels, + ) + register.MustRegister(m) + return m +} + +// NewGauge will register a Gauge metric to specified registry and return it. +// If registry is not specified, it will register metric to default prometheus registry. +func NewGauge(subsystem, name, help string, labels []string, register prometheus.Registerer) *prometheus.GaugeVec { + if register == nil { + register = prometheus.DefaultRegisterer + } + m := prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: name, + Help: help, + }, + labels, + ) + register.MustRegister(m) + return m +} + +// NewSummary will register a Summary metric to specified registry and return it. +// If registry is not specified, it will register metric to default prometheus registry. +func NewSummary(subsystem, name, help string, labels []string, objectives map[float64]float64, register prometheus.Registerer) *prometheus.SummaryVec { + if register == nil { + register = prometheus.DefaultRegisterer + } + m := prometheus.NewSummaryVec( + prometheus.SummaryOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: name, + Help: help, + Objectives: objectives, + }, + labels, + ) + register.MustRegister(m) + return m +} + +// NewHistogram will register a Histogram metric to specified registry and return it. +// If registry is not specified, it will register metric to default prometheus registry. +func NewHistogram(subsystem, name, help string, labels []string, buckets []float64, register prometheus.Registerer) *prometheus.HistogramVec { + if register == nil { + register = prometheus.DefaultRegisterer + } + m := prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: namespace, + Subsystem: subsystem, + Name: name, + Help: help, + Buckets: buckets, + }, + labels, + ) + register.MustRegister(m) + return m +} diff --git a/pkg/timeutils/time_util.go b/pkg/timeutils/time_util.go index 53a6886bd..c18c0a956 100644 --- a/pkg/timeutils/time_util.go +++ b/pkg/timeutils/time_util.go @@ -24,3 +24,8 @@ import ( func GetCurrentTimeMillis() int64 { return time.Now().UnixNano() / time.Millisecond.Nanoseconds() } + +// SinceInMilliseconds gets the time since the specified start in milliseconds. +func SinceInMilliseconds(start time.Time) float64 { + return float64(time.Since(start).Nanoseconds()) / float64(time.Millisecond.Nanoseconds()) +} diff --git a/pkg/util/metrics_util.go b/pkg/util/metrics_util.go deleted file mode 100644 index 9d1d27a2a..000000000 --- a/pkg/util/metrics_util.go +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright The Dragonfly Authors. - * - * Licensed 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 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/supernode/daemon/daemon.go b/supernode/daemon/daemon.go index 21490476b..13e2ca8a9 100644 --- a/supernode/daemon/daemon.go +++ b/supernode/daemon/daemon.go @@ -26,6 +26,7 @@ import ( "github.com/dragonflyoss/Dragonfly/supernode/server" "github.com/go-openapi/strfmt" + "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" ) @@ -47,7 +48,7 @@ func New(cfg *config.Config) (*Daemon, error) { return nil, err } - s, err := server.New(cfg) + s, err := server.New(cfg, prometheus.DefaultRegisterer) if err != nil { return nil, err } diff --git a/supernode/daemon/mgr/dfgettask/manager.go b/supernode/daemon/mgr/dfgettask/manager.go index b417e6fcb..4807264ff 100644 --- a/supernode/daemon/mgr/dfgettask/manager.go +++ b/supernode/daemon/mgr/dfgettask/manager.go @@ -22,27 +22,53 @@ import ( "github.com/dragonflyoss/Dragonfly/apis/types" "github.com/dragonflyoss/Dragonfly/pkg/errortypes" + "github.com/dragonflyoss/Dragonfly/pkg/metricsutils" "github.com/dragonflyoss/Dragonfly/pkg/stringutils" "github.com/dragonflyoss/Dragonfly/pkg/syncmap" + "github.com/dragonflyoss/Dragonfly/supernode/config" "github.com/dragonflyoss/Dragonfly/supernode/daemon/mgr" dutil "github.com/dragonflyoss/Dragonfly/supernode/daemon/util" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" ) var _ mgr.DfgetTaskMgr = &Manager{} +type metrics struct { + dfgetTasks *prometheus.GaugeVec + dfgetTasksRegisterCount *prometheus.CounterVec + dfgetTasksFailCount *prometheus.CounterVec +} + +func newMetrics(register prometheus.Registerer) *metrics { + return &metrics{ + dfgetTasks: metricsutils.NewGauge(config.SubsystemSupernode, "dfgettasks", + "Current status of dfgettasks", []string{"callsystem", "status"}, register), + + dfgetTasksRegisterCount: metricsutils.NewCounter(config.SubsystemSupernode, "dfgettasks_registered_total", + "Total times of registering dfgettasks", []string{"callsystem"}, register), + + dfgetTasksFailCount: metricsutils.NewCounter(config.SubsystemSupernode, "dfgettasks_failed_total", + "Total failure times of dfgettasks", []string{"callsystem"}, register), + } +} + // Manager is an implementation of the interface of DfgetTaskMgr. type Manager struct { + cfg *config.Config dfgetTaskStore *dutil.Store ptoc *syncmap.SyncMap + metrics *metrics } // NewManager returns a new Manager. -func NewManager() (*Manager, error) { +func NewManager(cfg *config.Config, register prometheus.Registerer) (*Manager, error) { return &Manager{ + cfg: cfg, dfgetTaskStore: dutil.NewStore(), ptoc: syncmap.NewSyncMap(), + metrics: newMetrics(register), }, nil } @@ -73,6 +99,13 @@ func (dtm *Manager) Add(ctx context.Context, dfgetTask *types.DfGetTask) error { dtm.ptoc.Add(generatePeerKey(dfgetTask.PeerID, dfgetTask.TaskID), dfgetTask.CID) dtm.dfgetTaskStore.Put(key, dfgetTask) + + // If dfget task is created by supernode cdn, don't update metrics. + if !dtm.cfg.IsSuperPID(dfgetTask.PeerID) || !dtm.cfg.IsSuperCID(dfgetTask.CID) { + dtm.metrics.dfgetTasks.WithLabelValues(dfgetTask.CallSystem, dfgetTask.Status).Inc() + dtm.metrics.dfgetTasksRegisterCount.WithLabelValues(dfgetTask.CallSystem).Inc() + } + return nil } @@ -103,7 +136,7 @@ func (dtm *Manager) Delete(ctx context.Context, clientID, taskID string) error { return err } dtm.ptoc.Delete(generatePeerKey(dfgetTask.PeerID, dfgetTask.TaskID)) - + dtm.metrics.dfgetTasks.WithLabelValues(dfgetTask.CallSystem, dfgetTask.Status).Dec() return dtm.dfgetTaskStore.Delete(key) } @@ -115,9 +148,16 @@ func (dtm *Manager) UpdateStatus(ctx context.Context, clientID, taskID, status s } if dfgetTask.Status != types.DfGetTaskStatusSUCCESS { + dtm.metrics.dfgetTasks.WithLabelValues(dfgetTask.CallSystem, dfgetTask.Status).Dec() + dtm.metrics.dfgetTasks.WithLabelValues(dfgetTask.CallSystem, status).Inc() dfgetTask.Status = status } + // Add the total failed count. + if dfgetTask.Status == types.DfGetTaskStatusFAILED { + dtm.metrics.dfgetTasksFailCount.WithLabelValues(dfgetTask.CallSystem).Inc() + } + return nil } diff --git a/supernode/daemon/mgr/dfgettask/manager_test.go b/supernode/daemon/mgr/dfgettask/manager_test.go index 83400099c..e21ea0a36 100644 --- a/supernode/daemon/mgr/dfgettask/manager_test.go +++ b/supernode/daemon/mgr/dfgettask/manager_test.go @@ -22,8 +22,11 @@ import ( "github.com/dragonflyoss/Dragonfly/apis/types" "github.com/dragonflyoss/Dragonfly/pkg/errortypes" + "github.com/dragonflyoss/Dragonfly/supernode/config" "github.com/go-check/check" + "github.com/prometheus/client_golang/prometheus" + prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" ) func Test(t *testing.T) { @@ -35,61 +38,198 @@ func init() { } type DfgetTaskMgrTestSuite struct { - manager *Manager + cfg *config.Config } -// SetUpSuite does common setup in the beginning of each test. func (s *DfgetTaskMgrTestSuite) SetUpSuite(c *check.C) { - s.manager, _ = NewManager() + s.cfg = config.NewConfig() + s.cfg.SetCIDPrefix("127.0.0.1") } -func (s *DfgetTaskMgrTestSuite) TestDfgetTaskMgr(c *check.C) { - clientID := "foo" - taskID := "00c4e7b174af7ed61c414b36ef82810ac0c98142c03e5748c00e1d1113f3c882" - - // Add - dfgetTask := &types.DfGetTask{ - CID: clientID, - Path: "/peer/file/taskFileName", - PieceSize: 4 * 1024 * 1024, - TaskID: taskID, - PeerID: "foo-192.168.10.11-1553838710990554281", +func (s *DfgetTaskMgrTestSuite) TestDfgetTaskAdd(c *check.C) { + manager, _ := NewManager(s.cfg, prometheus.NewRegistry()) + dfgetTasks := manager.metrics.dfgetTasks + dfgetTasksRegisterCount := manager.metrics.dfgetTasksRegisterCount + + var testCases = []struct { + dfgetTask *types.DfGetTask + Expect *types.DfGetTask + }{ + { + dfgetTask: &types.DfGetTask{ + CID: "foo", + CallSystem: "foo", + Dfdaemon: true, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test1", + PeerID: "peer1", + }, + Expect: &types.DfGetTask{ + CID: "foo", + CallSystem: "foo", + Dfdaemon: true, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test1", + PeerID: "peer1", + Status: types.DfGetTaskStatusWAITING, + }, + }, + { + dfgetTask: &types.DfGetTask{ + CID: "bar", + CallSystem: "bar", + Dfdaemon: false, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test2", + PeerID: "peer2", + }, + Expect: &types.DfGetTask{ + CID: "bar", + CallSystem: "bar", + Dfdaemon: false, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test2", + PeerID: "peer2", + Status: types.DfGetTaskStatusWAITING, + }, + }, } - err := s.manager.Add(context.Background(), dfgetTask) - c.Check(err, check.IsNil) - - // Get - dt, err := s.manager.Get(context.Background(), clientID, taskID) - c.Check(err, check.IsNil) - c.Check(dt, check.DeepEquals, &types.DfGetTask{ - CID: clientID, - Path: "/peer/file/taskFileName", - PieceSize: 4 * 1024 * 1024, - TaskID: taskID, - Status: types.DfGetTaskStatusWAITING, - PeerID: "foo-192.168.10.11-1553838710990554281", - }) - - // UpdateStatus - err = s.manager.UpdateStatus(context.Background(), clientID, taskID, types.DfGetTaskStatusSUCCESS) - c.Check(err, check.IsNil) - - dt, err = s.manager.Get(context.Background(), clientID, taskID) - c.Check(err, check.IsNil) - c.Check(dt, check.DeepEquals, &types.DfGetTask{ - CID: clientID, - Path: "/peer/file/taskFileName", - PieceSize: 4 * 1024 * 1024, - TaskID: taskID, - Status: types.DfGetTaskStatusSUCCESS, - PeerID: "foo-192.168.10.11-1553838710990554281", - }) - - // Delete - err = s.manager.Delete(context.Background(), clientID, taskID) - c.Check(err, check.IsNil) - - _, err = s.manager.Get(context.Background(), clientID, taskID) - c.Check(errortypes.IsDataNotFound(err), check.Equals, true) + for _, tc := range testCases { + err := manager.Add(context.Background(), tc.dfgetTask) + c.Check(err, check.IsNil) + c.Assert(1, check.Equals, + int(prom_testutil.ToFloat64( + dfgetTasks.WithLabelValues(tc.dfgetTask.CallSystem, tc.dfgetTask.Status)))) + + c.Assert(1, check.Equals, + int(prom_testutil.ToFloat64( + dfgetTasksRegisterCount.WithLabelValues(tc.dfgetTask.CallSystem)))) + dt, err := manager.Get(context.Background(), tc.dfgetTask.CID, tc.dfgetTask.TaskID) + c.Check(err, check.IsNil) + c.Check(dt, check.DeepEquals, tc.Expect) + } +} + +func (s *DfgetTaskMgrTestSuite) TestDfgetTaskUpdate(c *check.C) { + manager, _ := NewManager(s.cfg, prometheus.NewRegistry()) + dfgetTasksFailCount := manager.metrics.dfgetTasksFailCount + + var testCases = []struct { + dfgetTask *types.DfGetTask + taskStatus string + Expect *types.DfGetTask + }{ + { + dfgetTask: &types.DfGetTask{ + CID: "foo", + CallSystem: "foo", + Dfdaemon: true, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test1", + PeerID: "peer1", + }, + taskStatus: types.DfGetTaskStatusFAILED, + Expect: &types.DfGetTask{ + CID: "foo", + CallSystem: "foo", + Dfdaemon: true, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test1", + PeerID: "peer1", + Status: types.DfGetTaskStatusFAILED, + }, + }, + { + dfgetTask: &types.DfGetTask{ + CID: "bar", + CallSystem: "bar", + Dfdaemon: false, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test2", + PeerID: "peer2", + }, + taskStatus: types.DfGetTaskStatusSUCCESS, + Expect: &types.DfGetTask{ + CID: "bar", + CallSystem: "bar", + Dfdaemon: false, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test2", + PeerID: "peer2", + Status: types.DfGetTaskStatusSUCCESS, + }, + }, + } + + for _, tc := range testCases { + err := manager.Add(context.Background(), tc.dfgetTask) + c.Check(err, check.IsNil) + + err = manager.UpdateStatus(context.Background(), tc.dfgetTask.CID, tc.dfgetTask.TaskID, tc.taskStatus) + c.Check(err, check.IsNil) + + if tc.taskStatus == types.DfGetTaskStatusFAILED { + c.Assert(1, check.Equals, + int(prom_testutil.ToFloat64( + dfgetTasksFailCount.WithLabelValues(tc.dfgetTask.CallSystem)))) + } + + dt, err := manager.Get(context.Background(), tc.dfgetTask.CID, tc.dfgetTask.TaskID) + c.Check(dt, check.DeepEquals, tc.Expect) + } +} + +func (s *DfgetTaskMgrTestSuite) TestDfgetTaskDelete(c *check.C) { + manager, _ := NewManager(s.cfg, prometheus.NewRegistry()) + dfgetTasks := manager.metrics.dfgetTasks + + var testCases = []struct { + dfgetTask *types.DfGetTask + }{ + { + dfgetTask: &types.DfGetTask{ + CID: "foo", + CallSystem: "foo", + Dfdaemon: false, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test1", + PeerID: "peer1", + }, + }, + { + dfgetTask: &types.DfGetTask{ + CID: "bar", + CallSystem: "bar", + Dfdaemon: true, + Path: "/peer/file/taskFileName", + PieceSize: 4 * 1024 * 1024, + TaskID: "test2", + PeerID: "peer2", + }, + }, + } + + for _, tc := range testCases { + err := manager.Add(context.Background(), tc.dfgetTask) + c.Check(err, check.IsNil) + + err = manager.Delete(context.Background(), tc.dfgetTask.CID, tc.dfgetTask.TaskID) + c.Check(err, check.IsNil) + c.Assert(0, check.Equals, + int(prom_testutil.ToFloat64( + dfgetTasks.WithLabelValues(tc.dfgetTask.CallSystem, tc.dfgetTask.Status)))) + + _, err = manager.Get(context.Background(), tc.dfgetTask.CID, tc.dfgetTask.TaskID) + c.Check(errortypes.IsDataNotFound(err), check.Equals, true) + } } diff --git a/supernode/daemon/mgr/peer/manager.go b/supernode/daemon/mgr/peer/manager.go index 969452fc1..6dffac9bf 100644 --- a/supernode/daemon/mgr/peer/manager.go +++ b/supernode/daemon/mgr/peer/manager.go @@ -23,26 +23,42 @@ import ( "github.com/dragonflyoss/Dragonfly/apis/types" "github.com/dragonflyoss/Dragonfly/pkg/errortypes" + "github.com/dragonflyoss/Dragonfly/pkg/metricsutils" "github.com/dragonflyoss/Dragonfly/pkg/netutils" "github.com/dragonflyoss/Dragonfly/pkg/stringutils" + "github.com/dragonflyoss/Dragonfly/supernode/config" "github.com/dragonflyoss/Dragonfly/supernode/daemon/mgr" dutil "github.com/dragonflyoss/Dragonfly/supernode/daemon/util" "github.com/go-openapi/strfmt" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" ) var _ mgr.PeerMgr = &Manager{} +type metrics struct { + peers *prometheus.GaugeVec +} + +func newMetrics(register prometheus.Registerer) *metrics { + return &metrics{ + peers: metricsutils.NewGauge(config.SubsystemSupernode, "peers", + "Current status of peers", []string{"peer"}, register), + } +} + // Manager is an implement of the interface of PeerMgr. type Manager struct { peerStore *dutil.Store + metrics *metrics } // NewManager return a new Manager Object. -func NewManager() (*Manager, error) { +func NewManager(register prometheus.Registerer) (*Manager, error) { return &Manager{ peerStore: dutil.NewStore(), + metrics: newMetrics(register), }, nil } @@ -67,6 +83,7 @@ func (pm *Manager) Register(ctx context.Context, peerCreateRequest *types.PeerCr Created: strfmt.DateTime(time.Now()), } pm.peerStore.Put(id, peerInfo) + pm.metrics.peers.WithLabelValues(peerInfo.IP.String()).Inc() return &types.PeerCreateResponse{ ID: id, @@ -75,11 +92,13 @@ func (pm *Manager) Register(ctx context.Context, peerCreateRequest *types.PeerCr // DeRegister a peer from p2p network. func (pm *Manager) DeRegister(ctx context.Context, peerID string) error { - if _, err := pm.getPeerInfo(peerID); err != nil { + peerInfo, err := pm.getPeerInfo(peerID) + if err != nil { return err } pm.peerStore.Delete(peerID) + pm.metrics.peers.WithLabelValues(peerInfo.IP.String()).Dec() return nil } diff --git a/supernode/daemon/mgr/peer/manager_test.go b/supernode/daemon/mgr/peer/manager_test.go index c8b90cfb5..db053e15d 100644 --- a/supernode/daemon/mgr/peer/manager_test.go +++ b/supernode/daemon/mgr/peer/manager_test.go @@ -24,8 +24,11 @@ import ( "github.com/dragonflyoss/Dragonfly/apis/types" "github.com/dragonflyoss/Dragonfly/pkg/errortypes" dutil "github.com/dragonflyoss/Dragonfly/supernode/daemon/util" + "github.com/dragonflyoss/Dragonfly/version" "github.com/go-check/check" + "github.com/prometheus/client_golang/prometheus" + prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" ) func Test(t *testing.T) { @@ -40,18 +43,20 @@ type PeerMgrTestSuite struct { } func (s *PeerMgrTestSuite) TestPeerMgr(c *check.C) { - manager, _ := NewManager() - + manager, _ := NewManager(prometheus.NewRegistry()) + peers := manager.metrics.peers // register request := &types.PeerCreateRequest{ IP: "192.168.10.11", HostName: "foo", Port: 65001, - Version: "v0.3.0", + Version: version.DFGetVersion, } resp, err := manager.Register(context.Background(), request) c.Check(err, check.IsNil) + c.Assert(1, check.Equals, + int(prom_testutil.ToFloat64(peers.WithLabelValues("192.168.10.11")))) // get id := resp.ID info, err := manager.Get(context.Background(), id) @@ -75,6 +80,9 @@ func (s *PeerMgrTestSuite) TestPeerMgr(c *check.C) { err = manager.DeRegister(context.Background(), id) c.Check(err, check.IsNil) + c.Assert(0, check.Equals, + int(prom_testutil.ToFloat64(peers.WithLabelValues("192.168.10.11")))) + // get info, err = manager.Get(context.Background(), id) c.Check(errortypes.IsDataNotFound(err), check.Equals, true) @@ -82,14 +90,14 @@ func (s *PeerMgrTestSuite) TestPeerMgr(c *check.C) { } func (s *PeerMgrTestSuite) TestGet(c *check.C) { - manager, _ := NewManager() + manager, _ := NewManager(prometheus.NewRegistry()) // register request := &types.PeerCreateRequest{ IP: "192.168.10.11", HostName: "foo", Port: 65001, - Version: "v0.3.0", + Version: version.DFGetVersion, } resp, err := manager.Register(context.Background(), request) c.Check(err, check.IsNil) @@ -120,13 +128,13 @@ func (s *PeerMgrTestSuite) TestGet(c *check.C) { } func (s *PeerMgrTestSuite) TestList(c *check.C) { - manager, _ := NewManager() + manager, _ := NewManager(prometheus.NewRegistry()) // the first data request := &types.PeerCreateRequest{ IP: "192.168.10.11", HostName: "foo", Port: 65001, - Version: "v0.3.0", + Version: version.DFGetVersion, } resp, err := manager.Register(context.Background(), request) c.Check(err, check.IsNil) @@ -139,7 +147,7 @@ func (s *PeerMgrTestSuite) TestList(c *check.C) { IP: "192.168.10.11", HostName: "foo2", Port: 65001, - Version: "v0.3.0", + Version: version.DFGetVersion, } resp, err = manager.Register(context.Background(), request) c.Check(err, check.IsNil) diff --git a/supernode/daemon/mgr/task/manager.go b/supernode/daemon/mgr/task/manager.go index d62b5e98a..e55dc44be 100644 --- a/supernode/daemon/mgr/task/manager.go +++ b/supernode/daemon/mgr/task/manager.go @@ -22,6 +22,7 @@ import ( "github.com/dragonflyoss/Dragonfly/apis/types" "github.com/dragonflyoss/Dragonfly/pkg/errortypes" + "github.com/dragonflyoss/Dragonfly/pkg/metricsutils" "github.com/dragonflyoss/Dragonfly/pkg/stringutils" "github.com/dragonflyoss/Dragonfly/pkg/syncmap" "github.com/dragonflyoss/Dragonfly/pkg/timeutils" @@ -32,6 +33,7 @@ import ( "github.com/dragonflyoss/Dragonfly/supernode/util" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" ) @@ -41,6 +43,34 @@ const ( var _ mgr.TaskMgr = &Manager{} +type metrics struct { + tasks *prometheus.GaugeVec + tasksRegisterCount *prometheus.CounterVec + triggerCdnCount *prometheus.CounterVec + triggerCdnFailCount *prometheus.CounterVec + scheduleDurationMilliSeconds *prometheus.HistogramVec +} + +func newMetrics(register prometheus.Registerer) *metrics { + return &metrics{ + tasks: metricsutils.NewGauge(config.SubsystemSupernode, "tasks", + "Current status of Supernode tasks", []string{"cdnstatus"}, register), + + tasksRegisterCount: metricsutils.NewCounter(config.SubsystemSupernode, "tasks_registered_total", + "Total times of registering tasks", []string{}, register), + + triggerCdnCount: metricsutils.NewCounter(config.SubsystemSupernode, "trigger_cdn_total", + "Total times of triggering cdn", []string{}, register), + + triggerCdnFailCount: metricsutils.NewCounter(config.SubsystemSupernode, "trigger_cdn_failed_total", + "Total failure times of triggering cdn", []string{}, register), + + scheduleDurationMilliSeconds: metricsutils.NewHistogram(config.SubsystemSupernode, "schedule_duration_milliseconds", + "Duration for task scheduling in milliseconds", []string{"peer"}, + prometheus.ExponentialBuckets(0.02, 2, 6), register), + } +} + // Manager is an implementation of the interface of TaskMgr. type Manager struct { cfg *config.Config @@ -56,11 +86,13 @@ type Manager struct { cdnMgr mgr.CDNMgr schedulerMgr mgr.SchedulerMgr OriginClient httpclient.OriginHTTPClient + metrics *metrics } // NewManager returns a new Manager Object. func NewManager(cfg *config.Config, peerMgr mgr.PeerMgr, dfgetTaskMgr mgr.DfgetTaskMgr, - progressMgr mgr.ProgressMgr, cdnMgr mgr.CDNMgr, schedulerMgr mgr.SchedulerMgr, originClient httpclient.OriginHTTPClient) (*Manager, error) { + progressMgr mgr.ProgressMgr, cdnMgr mgr.CDNMgr, schedulerMgr mgr.SchedulerMgr, + originClient httpclient.OriginHTTPClient, register prometheus.Registerer) (*Manager, error) { return &Manager{ cfg: cfg, taskStore: dutil.NewStore(), @@ -73,6 +105,7 @@ func NewManager(cfg *config.Config, peerMgr mgr.PeerMgr, dfgetTaskMgr mgr.DfgetT accessTimeMap: syncmap.NewSyncMap(), taskURLUnReachableStore: syncmap.NewSyncMap(), OriginClient: originClient, + metrics: newMetrics(register), }, nil } @@ -90,6 +123,7 @@ func (tm *Manager) Register(ctx context.Context, req *types.TaskCreateRequest) ( logrus.Infof("failed to add or update task with req %+v: %v", req, err) return nil, err } + tm.metrics.tasksRegisterCount.WithLabelValues().Inc() logrus.Debugf("success to get task info: %+v", task) // TODO: defer rollback the task update diff --git a/supernode/daemon/mgr/task/manager_test.go b/supernode/daemon/mgr/task/manager_test.go index e79c830f1..59c2b604d 100644 --- a/supernode/daemon/mgr/task/manager_test.go +++ b/supernode/daemon/mgr/task/manager_test.go @@ -29,6 +29,8 @@ import ( "github.com/go-check/check" "github.com/golang/mock/gomock" + "github.com/prometheus/client_golang/prometheus" + prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" ) func Test(t *testing.T) { @@ -66,9 +68,8 @@ func (s *TaskMgrTestSuite) SetUpSuite(c *check.C) { s.mockProgressMgr.EXPECT().InitProgress(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() s.mockOriginClient.EXPECT().GetContentLength(gomock.Any(), gomock.Any()).Return(int64(1000), 200, nil) cfg := config.NewConfig() - s.taskManager, _ = NewManager(cfg, s.mockPeerMgr, s.mockDfgetTaskMgr, - s.mockProgressMgr, s.mockCDNMgr, s.mockSchedulerMgr, s.mockOriginClient) + s.mockProgressMgr, s.mockCDNMgr, s.mockSchedulerMgr, s.mockOriginClient, prometheus.NewRegistry()) } func (s *TaskMgrTestSuite) TearDownSuite(c *check.C) { @@ -76,6 +77,7 @@ func (s *TaskMgrTestSuite) TearDownSuite(c *check.C) { } func (s *TaskMgrTestSuite) TestCheckTaskStatus(c *check.C) { + tasksRegisterCount := s.taskManager.metrics.tasksRegisterCount s.taskManager.taskStore = dutil.NewStore() req := &types.TaskCreateRequest{ CID: "cid", @@ -87,6 +89,8 @@ func (s *TaskMgrTestSuite) TestCheckTaskStatus(c *check.C) { } resp, err := s.taskManager.Register(context.Background(), req) c.Check(err, check.IsNil) + c.Assert(1, check.Equals, + int(prom_testutil.ToFloat64(tasksRegisterCount.WithLabelValues()))) isSuccess, err := s.taskManager.CheckTaskStatus(context.Background(), resp.ID) c.Check(err, check.IsNil) diff --git a/supernode/daemon/mgr/task/manager_util.go b/supernode/daemon/mgr/task/manager_util.go index a70db67c0..4e1fe414b 100644 --- a/supernode/daemon/mgr/task/manager_util.go +++ b/supernode/daemon/mgr/task/manager_util.go @@ -27,6 +27,7 @@ import ( "github.com/dragonflyoss/Dragonfly/pkg/errortypes" "github.com/dragonflyoss/Dragonfly/pkg/netutils" "github.com/dragonflyoss/Dragonfly/pkg/stringutils" + "github.com/dragonflyoss/Dragonfly/pkg/timeutils" "github.com/dragonflyoss/Dragonfly/supernode/config" "github.com/dragonflyoss/Dragonfly/supernode/daemon/mgr" "github.com/dragonflyoss/Dragonfly/supernode/util" @@ -109,6 +110,7 @@ func (tm *Manager) addOrUpdateTask(ctx context.Context, req *types.TaskCreateReq task.PieceTotal = int32((fileLength + (int64(pieceSize) - 1)) / int64(pieceSize)) tm.taskStore.Put(taskID, task) + tm.metrics.tasks.WithLabelValues(task.CdnStatus).Inc() return task, nil } @@ -160,6 +162,8 @@ func (tm *Manager) updateTask(taskID string, updateTaskInfo *types.TaskInfo) err // only update the task CdnStatus when the new CDNStatus and // the origin CDNStatus both not equals success + tm.metrics.tasks.WithLabelValues(task.CdnStatus).Dec() + tm.metrics.tasks.WithLabelValues(updateTaskInfo.CdnStatus).Inc() task.CdnStatus = updateTaskInfo.CdnStatus return nil } @@ -181,6 +185,8 @@ func (tm *Manager) updateTask(taskID string, updateTaskInfo *types.TaskInfo) err if pieceTotal != 0 { task.PieceTotal = pieceTotal } + tm.metrics.tasks.WithLabelValues(task.CdnStatus).Dec() + tm.metrics.tasks.WithLabelValues(updateTaskInfo.CdnStatus).Inc() task.CdnStatus = updateTaskInfo.CdnStatus return nil @@ -227,7 +233,9 @@ func (tm *Manager) triggerCdnSyncAction(ctx context.Context, task *types.TaskInf go func() { updateTaskInfo, err := tm.cdnMgr.TriggerCDN(ctx, task) + tm.metrics.triggerCdnCount.WithLabelValues().Inc() if err != nil { + tm.metrics.triggerCdnFailCount.WithLabelValues().Inc() logrus.Errorf("taskID(%s) trigger cdn get error: %v", task.ID, err) } tm.updateTask(task.ID, updateTaskInfo) @@ -322,12 +330,16 @@ func (tm *Manager) parseAvailablePeers(ctx context.Context, clientID string, tas return true, finishInfo, nil } + // Get peerName to represent peer in metrics. + peer, _ := tm.peerMgr.Get(context.Background(), dfgetTask.PeerID) // get scheduler pieceResult logrus.Debugf("start scheduler for taskID: %s clientID: %s", task.ID, clientID) + startTime := time.Now() pieceResult, err := tm.schedulerMgr.Schedule(ctx, task.ID, clientID, dfgetTask.PeerID) if err != nil { return false, nil, err } + tm.metrics.scheduleDurationMilliSeconds.WithLabelValues(peer.IP.String()).Observe(timeutils.SinceInMilliseconds(startTime)) logrus.Debugf("get scheduler result length(%d) with taskID(%s) and clientID(%s)", len(pieceResult), task.ID, clientID) var pieceInfos []*types.PieceInfo diff --git a/supernode/daemon/mgr/task/manager_util_test.go b/supernode/daemon/mgr/task/manager_util_test.go index 5edfc21b8..8de07404d 100644 --- a/supernode/daemon/mgr/task/manager_util_test.go +++ b/supernode/daemon/mgr/task/manager_util_test.go @@ -17,6 +17,8 @@ package task import ( + "context" + "github.com/dragonflyoss/Dragonfly/apis/types" "github.com/dragonflyoss/Dragonfly/supernode/config" "github.com/dragonflyoss/Dragonfly/supernode/daemon/mgr/mock" @@ -24,6 +26,8 @@ import ( "github.com/go-check/check" "github.com/golang/mock/gomock" + "github.com/prometheus/client_golang/prometheus" + prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" ) func init() { @@ -51,9 +55,9 @@ func (s *TaskUtilTestSuite) SetUpSuite(c *check.C) { s.mockProgressMgr = mock.NewMockProgressMgr(s.mockCtl) s.mockSchedulerMgr = mock.NewMockSchedulerMgr(s.mockCtl) s.mockOriginClient = cMock.NewMockOriginHTTPClient(s.mockCtl) - s.taskManager, _ = NewManager(config.NewConfig(), s.mockPeerMgr, s.mockDfgetTaskMgr, - s.mockProgressMgr, s.mockCDNMgr, s.mockSchedulerMgr, s.mockOriginClient) + s.mockProgressMgr, s.mockCDNMgr, s.mockSchedulerMgr, s.mockOriginClient, prometheus.NewRegistry()) + s.mockOriginClient.EXPECT().GetContentLength(gomock.Any(), gomock.Any()).Return(int64(1000), 200, nil) } @@ -123,3 +127,57 @@ func (s *TaskUtilTestSuite) TestEqualsTask(c *check.C) { c.Check(result, check.DeepEquals, v.result) } } + +func (s *TaskUtilTestSuite) TestTriggerCdnSyncAction(c *check.C) { + var err error + totalCounter := s.taskManager.metrics.triggerCdnCount + + var cases = []struct { + task *types.TaskInfo + err error + skip bool + total float64 + }{ + { + task: &types.TaskInfo{ + CdnStatus: types.TaskInfoCdnStatusRUNNING, + }, + err: nil, + skip: true, + }, + { + task: &types.TaskInfo{ + CdnStatus: types.TaskInfoCdnStatusSUCCESS, + }, + err: nil, + skip: true, + }, + { + task: &types.TaskInfo{ + ID: "foo", + CdnStatus: types.TaskInfoCdnStatusWAITING, + }, + err: nil, + skip: false, + total: 1, + }, + { + task: &types.TaskInfo{ + ID: "foo1", + CdnStatus: types.TaskInfoCdnStatusWAITING, + }, + err: nil, + skip: false, + total: 2, + }, + } + + for _, tc := range cases { + err = s.taskManager.triggerCdnSyncAction(context.Background(), tc.task) + c.Assert(err, check.Equals, tc.err) + if !tc.skip { + c.Assert(tc.total, check.Equals, + int(prom_testutil.ToFloat64(totalCounter.WithLabelValues()))) + } + } +} diff --git a/supernode/server/metrics.go b/supernode/server/metrics.go index da0b70850..20aa7eb8d 100644 --- a/supernode/server/metrics.go +++ b/supernode/server/metrics.go @@ -19,14 +19,14 @@ package server import ( "net/http" - "github.com/dragonflyoss/Dragonfly/pkg/util" + "github.com/dragonflyoss/Dragonfly/pkg/metricsutils" "github.com/dragonflyoss/Dragonfly/supernode/config" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) -// metrics defines three prometheus metrics for monitoring http handler status +// metrics defines some prometheus metrics for monitoring supernode type metrics struct { requestCounter *prometheus.CounterVec requestDuration *prometheus.HistogramVec @@ -34,22 +34,22 @@ type metrics struct { responseSize *prometheus.HistogramVec } -func newMetrics() *metrics { +func newMetrics(register prometheus.Registerer) *metrics { return &metrics{ - requestCounter: util.NewCounter(config.SubsystemSupernode, "http_requests_total", - "Counter of HTTP requests.", []string{"code", "handler", "method"}, + requestCounter: metricsutils.NewCounter(config.SubsystemSupernode, "http_requests_total", + "Counter of HTTP requests.", []string{"code", "handler"}, register, ), - 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}, + requestDuration: metricsutils.NewHistogram(config.SubsystemSupernode, "http_request_duration_seconds", + "Histogram of latencies for HTTP requests.", []string{"handler"}, + []float64{.1, .2, .4, 1, 3, 8, 20, 60, 120}, register, ), - 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), + requestSize: metricsutils.NewHistogram(config.SubsystemSupernode, "http_request_size_bytes", + "Histogram of request size for HTTP requests.", []string{"handler"}, + prometheus.ExponentialBuckets(100, 10, 8), register, ), - 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), + responseSize: metricsutils.NewHistogram(config.SubsystemSupernode, "http_response_size_bytes", + "Histogram of response size for HTTP requests.", []string{"handler"}, + prometheus.ExponentialBuckets(100, 10, 8), register, ), } } diff --git a/supernode/server/router.go b/supernode/server/router.go index 6f9f99440..b4cc49428 100644 --- a/supernode/server/router.go +++ b/supernode/server/router.go @@ -26,13 +26,14 @@ import ( "github.com/dragonflyoss/Dragonfly/version" "github.com/gorilla/mux" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) // versionMatcher defines to parse version url path. const versionMatcher = "/v{version:[0-9.]+}" -var m = newMetrics() +var m = newMetrics(prometheus.DefaultRegisterer) func initRoute(s *Server) *mux.Router { r := mux.NewRouter() @@ -54,6 +55,7 @@ func initRoute(s *Server) *mux.Router { {Method: http.MethodGet, Path: "/peers/{id}", HandlerFunc: s.getPeer}, {Method: http.MethodGet, Path: "/peers", HandlerFunc: s.listPeers}, + // metrics {Method: http.MethodGet, Path: "/metrics", HandlerFunc: handleMetrics}, } diff --git a/supernode/server/router_test.go b/supernode/server/router_test.go index 3c176e48f..83711cdfb 100644 --- a/supernode/server/router_test.go +++ b/supernode/server/router_test.go @@ -34,6 +34,7 @@ import ( "github.com/go-check/check" "github.com/gorilla/mux" + "github.com/prometheus/client_golang/prometheus" prom_testutil "github.com/prometheus/client_golang/prometheus/testutil" ) @@ -67,7 +68,7 @@ func (rs *RouterTestSuite) SetUpSuite(c *check.C) { Plugins: nil, Storages: nil, } - s, err := New(testConf) + s, err := New(testConf, prometheus.NewRegistry()) c.Check(err, check.IsNil) version.DFVersion = &types.DragonflyVersion{ Version: "test", @@ -135,13 +136,13 @@ func (rs *RouterTestSuite) TestHTTPMetrics(c *check.C) { counter := m.requestCounter c.Assert(1, check.Equals, - int(prom_testutil.ToFloat64(counter.WithLabelValues(strconv.Itoa(http.StatusOK), "/metrics", "get")))) + int(prom_testutil.ToFloat64(counter.WithLabelValues(strconv.Itoa(http.StatusOK), "/metrics")))) for i := 0; i < 5; i++ { code, _, err := httputils.Get("http://"+rs.addr+"/_ping", 0) c.Check(err, check.IsNil) c.Assert(code, check.Equals, 200) c.Assert(i+1, check.Equals, - int(prom_testutil.ToFloat64(counter.WithLabelValues(strconv.Itoa(http.StatusOK), "/_ping", "get")))) + int(prom_testutil.ToFloat64(counter.WithLabelValues(strconv.Itoa(http.StatusOK), "/_ping")))) } } diff --git a/supernode/server/server.go b/supernode/server/server.go index 90ed89202..486b71457 100644 --- a/supernode/server/server.go +++ b/supernode/server/server.go @@ -34,6 +34,7 @@ import ( "github.com/dragonflyoss/Dragonfly/supernode/store" "github.com/dragonflyoss/Dragonfly/version" + "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" ) @@ -48,7 +49,10 @@ type Server struct { } // New creates a brand new server instance. -func New(cfg *config.Config) (*Server, error) { +func New(cfg *config.Config, register prometheus.Registerer) (*Server, error) { + // register supernode build information + version.NewBuildInfo("supernode", register) + sm, err := store.NewManager(cfg) if err != nil { return nil, err @@ -59,13 +63,12 @@ func New(cfg *config.Config) (*Server, error) { } originClient := httpclient.NewOriginClient() - - peerMgr, err := peer.NewManager() + peerMgr, err := peer.NewManager(register) if err != nil { return nil, err } - dfgetTaskMgr, err := dfgettask.NewManager() + dfgetTaskMgr, err := dfgettask.NewManager(cfg, register) if err != nil { return nil, err } @@ -85,7 +88,8 @@ func New(cfg *config.Config) (*Server, error) { return nil, err } - taskMgr, err := task.NewManager(cfg, peerMgr, dfgetTaskMgr, progressMgr, cdnMgr, schedulerMgr, originClient) + taskMgr, err := task.NewManager(cfg, peerMgr, dfgetTaskMgr, progressMgr, cdnMgr, + schedulerMgr, originClient, register) if err != nil { return nil, err } @@ -112,8 +116,6 @@ func (s *Server) Start() error { return err } - // register supernode build information - version.NewBuildInfo("supernode") server := &http.Server{ Handler: router, ReadTimeout: time.Minute * 10, diff --git a/test/api_metrics_test.go b/test/api_metrics_test.go index 09040de63..1aab3609c 100644 --- a/test/api_metrics_test.go +++ b/test/api_metrics_test.go @@ -57,26 +57,26 @@ func (s *APIMetricsSuite) TestMetrics(c *check.C) { // TestMetricsRequestTotal tests http-related metrics. func (s *APIMetricsSuite) TestHttpMetrics(c *check.C) { - requestCounter := `dragonfly_supernode_http_requests_total{code="%d",handler="%s",method="%s"}` - responseSizeSum := `dragonfly_supernode_http_response_size_bytes_sum{code="%d",handler="%s",method="%s"}` - responseSizeCount := `dragonfly_supernode_http_response_size_bytes_count{code="%d",handler="%s",method="%s"}` - requestSizeCount := `dragonfly_supernode_http_request_size_bytes_count{code="%d",handler="%s",method="%s"}` + requestCounter := `dragonfly_supernode_http_requests_total{code="%d",handler="%s"}` + responseSizeSum := `dragonfly_supernode_http_response_size_bytes_sum{handler="%s"}` + responseSizeCount := `dragonfly_supernode_http_response_size_bytes_count{handler="%s"}` + requestSizeCount := `dragonfly_supernode_http_request_size_bytes_count{handler="%s"}` resp, err := request.Get("/_ping") c.Assert(err, check.IsNil) CheckRespStatus(c, resp, 200) // Get httpRequest counter value equals 1. - CheckMetric(c, fmt.Sprintf(requestCounter, 200, "/_ping", "get"), 1) + CheckMetric(c, fmt.Sprintf(requestCounter, 200, "/_ping"), 1) // Get httpResponse size sum value equals 2. - CheckMetric(c, fmt.Sprintf(responseSizeSum, 200, "/_ping", "get"), 2) + CheckMetric(c, fmt.Sprintf(responseSizeSum, "/_ping"), 2) // Get httpResponse size count value equals 1. - CheckMetric(c, fmt.Sprintf(responseSizeCount, 200, "/_ping", "get"), 1) + CheckMetric(c, fmt.Sprintf(responseSizeCount, "/_ping"), 1) // Get httpRequest size count value equals 1. - CheckMetric(c, fmt.Sprintf(requestSizeCount, 200, "/_ping", "get"), 1) + CheckMetric(c, fmt.Sprintf(requestSizeCount, "/_ping"), 1) } // TestBuildInfoMetrics tests build info metric. diff --git a/version/version.go b/version/version.go index fa850ab6b..7d9a91c91 100644 --- a/version/version.go +++ b/version/version.go @@ -28,7 +28,9 @@ import ( "text/template" "github.com/dragonflyoss/Dragonfly/apis/types" - "github.com/dragonflyoss/Dragonfly/pkg/util" + "github.com/dragonflyoss/Dragonfly/pkg/metricsutils" + + "github.com/prometheus/client_golang/prometheus" ) var ( @@ -106,11 +108,12 @@ func Print(program string) string { } // NewBuildInfo register a collector which exports metrics about version and build information. -func NewBuildInfo(program string) { - buildInfo := util.NewGauge(program, "build_info", +func NewBuildInfo(program string, registerer prometheus.Registerer) { + buildInfo := metricsutils.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"}, + registerer, ) buildInfo.WithLabelValues(version, revision, os, arch, goVersion).Set(1) }