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");