From e4c36d407fd1270f8e04aab648bf9ce108139332 Mon Sep 17 00:00:00 2001
From: OutOfEastGate <1946066280@qq.com>
Date: Wed, 26 Apr 2023 22:18:48 +0800
Subject: [PATCH] feat: fix prometheus filter bugs (#1792)
* fix: fix prometheus
* fix: count latency with prefix api
* fix: latency should not be counted when startTime is nil
---
controllers/base.go | 11 ++++++++
main.go | 1 +
object/prometheus.go | 14 +++++-----
routers/prometheus_filter.go | 52 +++++++++++++-----------------------
web/src/SystemInfo.js | 4 +--
5 files changed, 40 insertions(+), 42 deletions(-)
diff --git a/controllers/base.go b/controllers/base.go
index bbe51526..ae4b88f8 100644
--- a/controllers/base.go
+++ b/controllers/base.go
@@ -183,3 +183,14 @@ func wrapErrorResponse(err error) *Response {
return &Response{Status: "error", Msg: err.Error()}
}
}
+
+func (c *ApiController) Finish() {
+ if strings.HasPrefix(c.Ctx.Input.URL(), "/api") {
+ startTime := c.Ctx.Input.GetData("startTime")
+ if startTime != nil {
+ latency := time.Since(startTime.(time.Time)).Milliseconds()
+ object.ApiLatency.WithLabelValues(c.Ctx.Input.Method(), c.Ctx.Input.URL()).Observe(float64(latency))
+ }
+ }
+ c.Controller.Finish()
+}
diff --git a/main.go b/main.go
index 09be0544..1b29fee1 100644
--- a/main.go
+++ b/main.go
@@ -60,6 +60,7 @@ func main() {
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.AuthzFilter)
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
+ beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
beego.BConfig.WebConfig.Session.SessionOn = true
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
diff --git a/object/prometheus.go b/object/prometheus.go
index 59aad42a..179d13f0 100644
--- a/object/prometheus.go
+++ b/object/prometheus.go
@@ -24,8 +24,8 @@ import (
)
type PrometheusInfo struct {
- APIThroughput []GaugeVecInfo `json:"apiThroughput"`
- APILatency []HistogramVecInfo `json:"apiLatency"`
+ ApiThroughput []GaugeVecInfo `json:"apiThroughput"`
+ ApiLatency []HistogramVecInfo `json:"apiLatency"`
TotalThroughput float64 `json:"totalThroughput"`
}
@@ -43,12 +43,12 @@ type HistogramVecInfo struct {
}
var (
- APIThroughput = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ ApiThroughput = promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: "casdoor_api_throughput",
Help: "The throughput of each api access",
}, []string{"path", "method"})
- APILatency = promauto.NewHistogramVec(prometheus.HistogramOpts{
+ ApiLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{
Name: "casdoor_api_latency",
Help: "API processing latency in milliseconds",
}, []string{"path", "method"})
@@ -73,7 +73,7 @@ func ClearThroughputPerSecond() {
// Clear the throughput every second
ticker := time.NewTicker(time.Second)
for range ticker.C {
- APIThroughput.Reset()
+ ApiThroughput.Reset()
TotalThroughput.Set(0)
}
}
@@ -87,9 +87,9 @@ func GetPrometheusInfo() (*PrometheusInfo, error) {
for _, metricFamily := range metricFamilies {
switch metricFamily.GetName() {
case "casdoor_api_throughput":
- res.APIThroughput = getGaugeVecInfo(metricFamily)
+ res.ApiThroughput = getGaugeVecInfo(metricFamily)
case "casdoor_api_latency":
- res.APILatency = getHistogramVecInfo(metricFamily)
+ res.ApiLatency = getHistogramVecInfo(metricFamily)
case "casdoor_total_throughput":
res.TotalThroughput = metricFamily.GetMetric()[0].GetGauge().GetValue()
}
diff --git a/routers/prometheus_filter.go b/routers/prometheus_filter.go
index 860a33ca..6bc4b6e4 100644
--- a/routers/prometheus_filter.go
+++ b/routers/prometheus_filter.go
@@ -2,46 +2,14 @@ package routers
import (
"fmt"
- "net/http"
"strings"
"time"
+ "github.com/beego/beego/context"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
-type PrometheusMiddleWareWrapper struct {
- handler http.Handler
-}
-
-func PrometheusMiddleWare(h http.Handler) http.Handler {
- return &PrometheusMiddleWareWrapper{
- handler: h,
- }
-}
-
-func (p PrometheusMiddleWareWrapper) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- method := req.Method
- endpoint := req.URL.Path
- if strings.HasPrefix(endpoint, "/api/metrics") {
- systemInfo, err := util.GetSystemInfo()
- if err == nil {
- recordSystemInfo(systemInfo)
- }
- p.handler.ServeHTTP(w, req)
- return
- }
-
- if strings.HasPrefix(endpoint, "/api") {
- start := time.Now()
- p.handler.ServeHTTP(w, req)
- latency := time.Since(start).Milliseconds()
- object.TotalThroughput.Inc()
- object.APILatency.WithLabelValues(endpoint, method).Observe(float64(latency))
- object.APIThroughput.WithLabelValues(endpoint, method).Inc()
- }
-}
-
func recordSystemInfo(systemInfo *util.SystemInfo) {
for i, value := range systemInfo.CpuUsage {
object.CpuUsage.WithLabelValues(fmt.Sprintf("%d", i)).Set(value)
@@ -49,3 +17,21 @@ func recordSystemInfo(systemInfo *util.SystemInfo) {
object.MemoryUsage.WithLabelValues("memoryUsed").Set(float64(systemInfo.MemoryUsed))
object.MemoryUsage.WithLabelValues("memoryTotal").Set(float64(systemInfo.MemoryTotal))
}
+
+func PrometheusFilter(ctx *context.Context) {
+ method := ctx.Input.Method()
+ path := ctx.Input.URL()
+ if strings.HasPrefix(path, "/api/metrics") {
+ systemInfo, err := util.GetSystemInfo()
+ if err == nil {
+ recordSystemInfo(systemInfo)
+ }
+ return
+ }
+
+ if strings.HasPrefix(path, "/api") {
+ ctx.Input.SetData("startTime", time.Now())
+ object.TotalThroughput.Inc()
+ object.ApiThroughput.WithLabelValues(path, method).Inc()
+ }
+}
diff --git a/web/src/SystemInfo.js b/web/src/SystemInfo.js
index 3cb808d9..3e77eff7 100644
--- a/web/src/SystemInfo.js
+++ b/web/src/SystemInfo.js
@@ -87,9 +87,9 @@ class SystemInfo extends React.Component {
;
- const latencyUi = this.state.prometheusInfo.apiLatency.length <= 0 ? :
+ const latencyUi = this.state.prometheusInfo.apiLatency === null || this.state.prometheusInfo.apiLatency?.length <= 0 ? :
;
- const throughputUi = this.state.prometheusInfo.apiLatency.length <= 0 ? :
+ const throughputUi = this.state.prometheusInfo.apiThroughput === null || this.state.prometheusInfo.apiThroughput?.length <= 0 ? :
;
const link = this.state.versionInfo?.version !== "" ? `https://github.com/casdoor/casdoor/releases/tag/${this.state.versionInfo?.version}` : "";
let versionText = this.state.versionInfo?.version !== "" ? this.state.versionInfo?.version : i18next.t("system:Unknown version");