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
This commit is contained in:
OutOfEastGate 2023-04-26 22:18:48 +08:00 committed by GitHub
parent 4c1915b014
commit e4c36d407f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 42 deletions

View File

@ -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()
}

View File

@ -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"

View File

@ -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()
}

View File

@ -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()
}
}

View File

@ -87,9 +87,9 @@ class SystemInfo extends React.Component {
<br /> <br />
<Progress type="circle" percent={Number((Number(this.state.systemInfo.memoryUsed) / Number(this.state.systemInfo.memoryTotal) * 100).toFixed(2))} />
</div>;
const latencyUi = this.state.prometheusInfo.apiLatency.length <= 0 ? <Spin size="large" /> :
const latencyUi = this.state.prometheusInfo.apiLatency === null || this.state.prometheusInfo.apiLatency?.length <= 0 ? <Spin size="large" /> :
<PrometheusInfoTable prometheusInfo={this.state.prometheusInfo} table={"latency"} />;
const throughputUi = this.state.prometheusInfo.apiLatency.length <= 0 ? <Spin size="large" /> :
const throughputUi = this.state.prometheusInfo.apiThroughput === null || this.state.prometheusInfo.apiThroughput?.length <= 0 ? <Spin size="large" /> :
<PrometheusInfoTable prometheusInfo={this.state.prometheusInfo} table={"throughput"} />;
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");