mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 10:45:47 +08:00
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:
parent
4c1915b014
commit
e4c36d407f
@ -183,3 +183,14 @@ func wrapErrorResponse(err error) *Response {
|
|||||||
return &Response{Status: "error", Msg: err.Error()}
|
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()
|
||||||
|
}
|
||||||
|
1
main.go
1
main.go
@ -60,6 +60,7 @@ func main() {
|
|||||||
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
|
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
|
||||||
beego.InsertFilter("*", beego.BeforeRouter, routers.AuthzFilter)
|
beego.InsertFilter("*", beego.BeforeRouter, routers.AuthzFilter)
|
||||||
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
|
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
|
||||||
|
beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
|
||||||
|
|
||||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||||
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
|
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
|
||||||
|
@ -24,8 +24,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PrometheusInfo struct {
|
type PrometheusInfo struct {
|
||||||
APIThroughput []GaugeVecInfo `json:"apiThroughput"`
|
ApiThroughput []GaugeVecInfo `json:"apiThroughput"`
|
||||||
APILatency []HistogramVecInfo `json:"apiLatency"`
|
ApiLatency []HistogramVecInfo `json:"apiLatency"`
|
||||||
TotalThroughput float64 `json:"totalThroughput"`
|
TotalThroughput float64 `json:"totalThroughput"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,12 +43,12 @@ type HistogramVecInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
APIThroughput = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
ApiThroughput = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
Name: "casdoor_api_throughput",
|
Name: "casdoor_api_throughput",
|
||||||
Help: "The throughput of each api access",
|
Help: "The throughput of each api access",
|
||||||
}, []string{"path", "method"})
|
}, []string{"path", "method"})
|
||||||
|
|
||||||
APILatency = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
ApiLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||||
Name: "casdoor_api_latency",
|
Name: "casdoor_api_latency",
|
||||||
Help: "API processing latency in milliseconds",
|
Help: "API processing latency in milliseconds",
|
||||||
}, []string{"path", "method"})
|
}, []string{"path", "method"})
|
||||||
@ -73,7 +73,7 @@ func ClearThroughputPerSecond() {
|
|||||||
// Clear the throughput every second
|
// Clear the throughput every second
|
||||||
ticker := time.NewTicker(time.Second)
|
ticker := time.NewTicker(time.Second)
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
APIThroughput.Reset()
|
ApiThroughput.Reset()
|
||||||
TotalThroughput.Set(0)
|
TotalThroughput.Set(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,9 +87,9 @@ func GetPrometheusInfo() (*PrometheusInfo, error) {
|
|||||||
for _, metricFamily := range metricFamilies {
|
for _, metricFamily := range metricFamilies {
|
||||||
switch metricFamily.GetName() {
|
switch metricFamily.GetName() {
|
||||||
case "casdoor_api_throughput":
|
case "casdoor_api_throughput":
|
||||||
res.APIThroughput = getGaugeVecInfo(metricFamily)
|
res.ApiThroughput = getGaugeVecInfo(metricFamily)
|
||||||
case "casdoor_api_latency":
|
case "casdoor_api_latency":
|
||||||
res.APILatency = getHistogramVecInfo(metricFamily)
|
res.ApiLatency = getHistogramVecInfo(metricFamily)
|
||||||
case "casdoor_total_throughput":
|
case "casdoor_total_throughput":
|
||||||
res.TotalThroughput = metricFamily.GetMetric()[0].GetGauge().GetValue()
|
res.TotalThroughput = metricFamily.GetMetric()[0].GetGauge().GetValue()
|
||||||
}
|
}
|
||||||
|
@ -2,46 +2,14 @@ package routers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/beego/beego/context"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"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) {
|
func recordSystemInfo(systemInfo *util.SystemInfo) {
|
||||||
for i, value := range systemInfo.CpuUsage {
|
for i, value := range systemInfo.CpuUsage {
|
||||||
object.CpuUsage.WithLabelValues(fmt.Sprintf("%d", i)).Set(value)
|
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("memoryUsed").Set(float64(systemInfo.MemoryUsed))
|
||||||
object.MemoryUsage.WithLabelValues("memoryTotal").Set(float64(systemInfo.MemoryTotal))
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -87,9 +87,9 @@ class SystemInfo extends React.Component {
|
|||||||
<br /> <br />
|
<br /> <br />
|
||||||
<Progress type="circle" percent={Number((Number(this.state.systemInfo.memoryUsed) / Number(this.state.systemInfo.memoryTotal) * 100).toFixed(2))} />
|
<Progress type="circle" percent={Number((Number(this.state.systemInfo.memoryUsed) / Number(this.state.systemInfo.memoryTotal) * 100).toFixed(2))} />
|
||||||
</div>;
|
</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"} />;
|
<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"} />;
|
<PrometheusInfoTable prometheusInfo={this.state.prometheusInfo} table={"throughput"} />;
|
||||||
const link = this.state.versionInfo?.version !== "" ? `https://github.com/casdoor/casdoor/releases/tag/${this.state.versionInfo?.version}` : "";
|
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");
|
let versionText = this.state.versionInfo?.version !== "" ? this.state.versionInfo?.version : i18next.t("system:Unknown version");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user