This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch refactor-with-go
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git


The following commit(s) were added to refs/heads/refactor-with-go by this push:
     new c483ed37 monitor -- Traffic Overview (#1047)
c483ed37 is described below

commit c483ed3702bee2b37ab41beb6081b9c8af5cca52
Author: 无言独上机房 <[email protected]>
AuthorDate: Wed Mar 22 08:51:23 2023 +0800

    monitor -- Traffic Overview (#1047)
---
 go.mod                                        |   6 +-
 go.sum                                        |   2 +
 pkg/admin/config/config.go                    |  21 ++++-
 pkg/admin/constant/const.go                   |   9 +++
 pkg/admin/handlers/service.go                 |  25 +++++-
 pkg/admin/model/monitor.go                    |  21 +++++
 pkg/admin/router/router.go                    |   2 +
 pkg/admin/services/monitor_service.go         |  23 ++++++
 pkg/admin/services/prometheus_service_impl.go | 110 ++++++++++++++++++++++++++
 pkg/monitor/prometheus/metrics.go             |  60 ++++++++++++++
 pkg/monitor/prometheus/types.go               |  23 ++++++
 11 files changed, 296 insertions(+), 6 deletions(-)

diff --git a/go.mod b/go.mod
index 92f3d0b2..26fbe51f 100644
--- a/go.mod
+++ b/go.mod
@@ -22,10 +22,12 @@ require (
        dubbo.apache.org/dubbo-go/v3 v3.0.2
        github.com/dubbogo/gost v1.11.25
        github.com/gin-gonic/gin v1.8.2
-       github.com/golang/mock v1.6.0
        github.com/golang-jwt/jwt/v4 v4.5.0
+       github.com/golang/mock v1.6.0
        github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
        github.com/mattbaird/jsonpatch v0.0.0-20200820163806-098863c1fc24
+       github.com/prometheus/client_golang v1.12.2
+       github.com/prometheus/common v0.32.1
        github.com/stretchr/testify v1.8.2
        github.com/tidwall/gjson v1.14.4
        go.uber.org/zap v1.24.0
@@ -104,9 +106,7 @@ require (
        github.com/pelletier/go-toml/v2 v2.0.6 // indirect
        github.com/pkg/errors v0.9.1 // indirect
        github.com/pmezard/go-difflib v1.0.0 // indirect
-       github.com/prometheus/client_golang v1.12.2 // 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/prometheus/statsd_exporter v0.21.0 // indirect
        github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // 
indirect
diff --git a/go.sum b/go.sum
index 955d3a2c..5528ead8 100644
--- a/go.sum
+++ b/go.sum
@@ -457,6 +457,7 @@ github.com/jonboulle/clockwork v0.1.0/go.mod 
h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
 github.com/jonboulle/clockwork v0.2.2/go.mod 
h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
 github.com/josharian/intern v1.0.0 
h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod 
h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/jpillora/backoff v1.0.0 
h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
 github.com/jpillora/backoff v1.0.0/go.mod 
h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/json-iterator/go v1.1.5/go.mod 
h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.6/go.mod 
h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -564,6 +565,7 @@ github.com/mschoch/smat v0.2.0/go.mod 
h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOl
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 
h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod 
h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod 
h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f 
h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod 
h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nacos-group/nacos-sdk-go v1.0.8/go.mod 
h1:hlAPn3UdzlxIlSILAyOXKxjFSvDJ9oLzTJ9hLAK1KzA=
 github.com/nacos-group/nacos-sdk-go v1.1.1 
h1:beczWcOoTaVBMgCgikqvZflrN5Xbw7pWAWpxl+VJGIA=
diff --git a/pkg/admin/config/config.go b/pkg/admin/config/config.go
index a19b43c8..72f1c34e 100644
--- a/pkg/admin/config/config.go
+++ b/pkg/admin/config/config.go
@@ -38,7 +38,13 @@ import (
 const conf = "./conf/dubboadmin.yml"
 
 type Config struct {
-       Admin Admin `yaml:"admin"`
+       Admin      Admin      `yaml:"admin"`
+       Prometheus Prometheus `yaml:"prometheus"`
+}
+
+type Prometheus struct {
+       Ip   string `json:"ip"`
+       Port string `json:"port"`
 }
 
 type Admin struct {
@@ -55,6 +61,11 @@ var (
        Group string
 )
 
+var (
+       PrometheusIp   string
+       PrometheusPort string
+)
+
 func LoadConfig() {
        path, err := filepath.Abs(conf)
        if err != nil {
@@ -69,6 +80,14 @@ func LoadConfig() {
        address := config.Admin.ConfigCenter
        registryAddress := config.Admin.Registry.Address
        metadataReportAddress := config.Admin.MetadataReport.Address
+       PrometheusIp = config.Prometheus.Ip
+       PrometheusPort = config.Prometheus.Port
+       if PrometheusIp == "" {
+               PrometheusIp = "127.0.0.1"
+       }
+       if PrometheusPort == "" {
+               PrometheusPort = "9090"
+       }
        if len(address) > 0 {
                c := newAddressConfig(address)
                factory, err := 
extension.GetConfigCenterFactory(c.getProtocol())
diff --git a/pkg/admin/constant/const.go b/pkg/admin/constant/const.go
index ccb4cc81..b4832a6d 100644
--- a/pkg/admin/constant/const.go
+++ b/pkg/admin/constant/const.go
@@ -68,3 +68,12 @@ const (
 )
 
 var Configs = set.NewSet(WeightKey, BalancingKey)
+
+const (
+       MetricsQps                        = "" // QPS
+       MetricsHttpRequestTotalCount      = "" // Total number of http requests
+       MetricsHttpRequestSuccessCount    = "" // Total number of http 
successful requests
+       MetricsHttpRequestOutOfTimeCount  = "" // Total number of http out of 
time requests
+       MetricsHttpRequestAddressNotFount = "" // Total number of HTTP requests 
where the address cannot be found
+       MetricsHttpRequestOtherException  = "" // Total number of other errors 
for http requests
+)
diff --git a/pkg/admin/handlers/service.go b/pkg/admin/handlers/service.go
index 948bb52d..fe7c6697 100644
--- a/pkg/admin/handlers/service.go
+++ b/pkg/admin/handlers/service.go
@@ -31,8 +31,9 @@ import (
 )
 
 var (
-       providerService services.ProviderService = 
&services.ProviderServiceImpl{}
-       consumerService services.ConsumerService = 
&services.ConsumerServiceImpl{}
+       providerService   services.ProviderService = 
&services.ProviderServiceImpl{}
+       consumerService   services.ConsumerService = 
&services.ConsumerServiceImpl{}
+       prometheusService services.MonitorService  = 
&services.PrometheusServiceImpl{}
 )
 
 func AllServices(c *gin.Context) {
@@ -145,3 +146,23 @@ func ServiceDetail(c *gin.Context) {
 func Version(c *gin.Context) {
        c.JSON(http.StatusOK, version.GetVersion())
 }
+
+func FlowMetrics(c *gin.Context) {
+       res, err := prometheusService.FlowMetrics()
+       if err != nil {
+               c.JSON(http.StatusInternalServerError, gin.H{
+                       "error": err.Error(),
+               })
+       }
+       c.JSON(http.StatusOK, res)
+}
+
+func ClusterMetrics(c *gin.Context) {
+       res, err := prometheusService.ClusterMetrics()
+       if err != nil {
+               c.JSON(http.StatusInternalServerError, gin.H{
+                       "error": err.Error(),
+               })
+       }
+       c.JSON(http.StatusOK, res)
+}
diff --git a/pkg/admin/model/monitor.go b/pkg/admin/model/monitor.go
new file mode 100644
index 00000000..3ff6b40e
--- /dev/null
+++ b/pkg/admin/model/monitor.go
@@ -0,0 +1,21 @@
+// 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 model
+
+type Response struct {
+       Status int    `json:"status"`
+       Data   string `json:"data"`
+}
diff --git a/pkg/admin/router/router.go b/pkg/admin/router/router.go
index 609bf3b8..ad948a84 100644
--- a/pkg/admin/router/router.go
+++ b/pkg/admin/router/router.go
@@ -31,6 +31,8 @@ func InitRouter() *gin.Engine {
        router.GET("api/dev/consumers", handlers.AllConsumers)
        router.GET("api/dev/service/:service", handlers.ServiceDetail)
        router.GET("/api/dev/version", handlers.Version)
+       router.GET("/api/dev/metrics/flow", handlers.FlowMetrics)
+       router.GET("/api/dev/metrics/cluster", handlers.ClusterMetrics)
 
        override := router.Group("/api/:env/rules/override")
        {
diff --git a/pkg/admin/services/monitor_service.go 
b/pkg/admin/services/monitor_service.go
new file mode 100644
index 00000000..5c377d41
--- /dev/null
+++ b/pkg/admin/services/monitor_service.go
@@ -0,0 +1,23 @@
+// 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 services
+
+package services
+
+import "github.com/apache/dubbo-admin/pkg/admin/model"
+
+type MonitorService interface {
+       FlowMetrics() ([]model.Response, error)    // Traffic overview
+       ClusterMetrics() ([]model.Response, error) // Cluster overview
+}
diff --git a/pkg/admin/services/prometheus_service_impl.go 
b/pkg/admin/services/prometheus_service_impl.go
new file mode 100644
index 00000000..9d272014
--- /dev/null
+++ b/pkg/admin/services/prometheus_service_impl.go
@@ -0,0 +1,110 @@
+// 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 services
+
+package services
+
+import (
+       "context"
+       "fmt"
+       "net/http"
+       "time"
+
+       "github.com/prometheus/client_golang/api"
+       prom_v1 "github.com/prometheus/client_golang/api/prometheus/v1"
+
+       "github.com/apache/dubbo-admin/pkg/admin/config"
+       "github.com/apache/dubbo-admin/pkg/admin/constant"
+       "github.com/apache/dubbo-admin/pkg/admin/model"
+       "github.com/apache/dubbo-admin/pkg/logger"
+       "github.com/apache/dubbo-admin/pkg/monitor/prometheus"
+)
+
+type PrometheusServiceImpl struct{}
+
+func (p *PrometheusServiceImpl) ClusterMetrics() ([]model.Response, error) {
+       return nil, nil
+}
+
+func (p *PrometheusServiceImpl) FlowMetrics() ([]model.Response, error) {
+       res := make([]model.Response, 5)
+       ip := config.PrometheusIp
+       port := config.PrometheusPort
+       address := fmt.Sprintf("http://%s:%s";, ip, port)
+       client, err := api.NewClient(api.Config{
+               Address: address,
+       })
+       if err != nil {
+               logger.Sugar().Errorf("Error creating client: %v\n", err)
+               return nil, err
+       }
+       v1api := prom_v1.NewAPI(client)
+       ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+       defer cancel()
+
+       vector1 := prometheus.FetchQuery(ctx, v1api, constant.MetricsQps, nil)
+       err = vector1.Err
+       if err != nil {
+               logger.Sugar().Errorf("Error query qps: %v\n", err)
+               res[0].Status = http.StatusInternalServerError
+               res[0].Data = ""
+       } else {
+               qps := float64(vector1.Vector[0].Value)
+               res[0].Status = http.StatusOK
+               res[0].Data = fmt.Sprintf("%d", int(qps))
+       }
+       vector2 := prometheus.FetchQuery(ctx, v1api, 
constant.MetricsHttpRequestSuccessCount, nil)
+       data1 := float64(vector2.Vector[0].Value)
+       vector3 := prometheus.FetchQuery(ctx, v1api, 
constant.MetricsHttpRequestTotalCount, nil)
+       data2 := float64(vector3.Vector[0].Value)
+       if vector2.Err != nil && vector3.Err != nil {
+               res[1].Status = http.StatusInternalServerError
+               res[1].Data = ""
+       } else {
+               res[1].Status = http.StatusOK
+               successRate := data1 / data2
+               res[1].Data = fmt.Sprintf("%0.2f", successRate)
+       }
+       vector4 := prometheus.FetchQuery(ctx, v1api, 
constant.MetricsHttpRequestOutOfTimeCount, nil)
+       data4 := float64(vector4.Vector[0].Value)
+       if vector4.Err != nil {
+               res[2].Status = http.StatusInternalServerError
+               res[2].Data = ""
+       } else {
+               res[2].Status = http.StatusOK
+               outOfTimeRate := data4 / data2
+               res[2].Data = fmt.Sprintf("%0.2f", outOfTimeRate)
+       }
+       vector5 := prometheus.FetchQuery(ctx, v1api, 
constant.MetricsHttpRequestAddressNotFount, nil)
+       data5 := float64(vector5.Vector[0].Value)
+       if vector5.Err != nil {
+               res[3].Status = http.StatusInternalServerError
+               res[3].Data = ""
+       } else {
+               res[3].Status = http.StatusOK
+               notFound := data5 / data2
+               res[3].Data = fmt.Sprintf("%0.2f", notFound)
+       }
+       vector6 := prometheus.FetchQuery(ctx, v1api, 
constant.MetricsHttpRequestOtherException, nil)
+       data6 := float64(vector6.Vector[0].Value)
+       if vector6.Err != nil {
+               res[4].Status = http.StatusInternalServerError
+               res[4].Data = ""
+       } else {
+               res[4].Status = http.StatusOK
+               other := data6 / data2
+               res[4].Data = fmt.Sprintf("%0.2f", other)
+       }
+       return res, nil
+}
diff --git a/pkg/monitor/prometheus/metrics.go 
b/pkg/monitor/prometheus/metrics.go
new file mode 100644
index 00000000..837cd37f
--- /dev/null
+++ b/pkg/monitor/prometheus/metrics.go
@@ -0,0 +1,60 @@
+// 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"
+       "fmt"
+       "time"
+
+       prom_v1 "github.com/prometheus/client_golang/api/prometheus/v1"
+       "github.com/prometheus/common/model"
+
+       "github.com/apache/dubbo-admin/pkg/logger"
+)
+
+func stitchingLabels(labels []string) string {
+       var labelsQ string
+       for i, labelsInstance := range labels {
+               if i == 0 {
+                       labelsQ += labelsInstance
+               } else {
+                       labelsQ += ", " + labelsInstance
+               }
+       }
+       return labelsQ
+}
+
+func FetchQuery(ctx context.Context, api prom_v1.API, metricName string, 
labels []string) Metric {
+       var query string
+       // Example: sum(my_counter{name=dubbo})
+       label := stitchingLabels(labels)
+       query = fmt.Sprintf("sum(%s{%s})", metricName, label)
+       logger.Sugar().Info(query)
+       result, warnings, err := api.Query(ctx, query, time.Now())
+       switch result.Type() {
+       case model.ValVector:
+               return Metric{Vector: result.(model.Vector)}
+       }
+       if len(warnings) > 0 {
+               logger.Sugar().Warnf("Warnings: %v", warnings)
+       }
+       if err != nil {
+               logger.Sugar().Errorf("Error query Prometheus: %v\n", err)
+               return Metric{Err: fmt.Errorf("Error query Prometheus: %v\n", 
err)}
+       }
+       return Metric{Err: fmt.Errorf("invalid query, matrix expected: %s", 
query)}
+}
diff --git a/pkg/monitor/prometheus/types.go b/pkg/monitor/prometheus/types.go
new file mode 100644
index 00000000..f6b13d45
--- /dev/null
+++ b/pkg/monitor/prometheus/types.go
@@ -0,0 +1,23 @@
+// 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 "github.com/prometheus/common/model"
+
+type Metric struct {
+       Vector model.Vector `json:"vector"`
+       Err    error        `json:"-"`
+}

Reply via email to