2020-08-10 15:04:57 +00:00
|
|
|
// Copyright 2020 beego
|
2020-08-07 14:14:07 +00:00
|
|
|
//
|
|
|
|
// Licensed 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"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
|
2020-10-08 09:17:15 +00:00
|
|
|
"github.com/astaxie/beego/client/orm"
|
2020-08-07 14:14:07 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// FilterChainBuilder is an extension point,
|
|
|
|
// when we want to support some configuration,
|
|
|
|
// please use this structure
|
2020-08-09 12:05:10 +00:00
|
|
|
// this Filter's behavior looks a little bit strange
|
|
|
|
// for example:
|
|
|
|
// if we want to records the metrics of QuerySetter
|
|
|
|
// actually we only records metrics of invoking "QueryTable" and "QueryTableWithCtx"
|
2020-08-07 14:14:07 +00:00
|
|
|
type FilterChainBuilder struct {
|
|
|
|
summaryVec prometheus.ObserverVec
|
2020-10-04 14:16:19 +00:00
|
|
|
AppName string
|
|
|
|
ServerName string
|
|
|
|
RunMode string
|
2020-08-07 14:14:07 +00:00
|
|
|
}
|
|
|
|
|
2020-10-04 14:16:19 +00:00
|
|
|
func (builder *FilterChainBuilder) FilterChain(next orm.Filter) orm.Filter {
|
|
|
|
|
|
|
|
builder.summaryVec = prometheus.NewSummaryVec(prometheus.SummaryOpts{
|
2020-08-07 14:14:07 +00:00
|
|
|
Name: "beego",
|
|
|
|
Subsystem: "orm_operation",
|
|
|
|
ConstLabels: map[string]string{
|
2020-10-04 14:16:19 +00:00
|
|
|
"server": builder.ServerName,
|
|
|
|
"env": builder.RunMode,
|
|
|
|
"appname": builder.AppName,
|
2020-08-07 14:14:07 +00:00
|
|
|
},
|
|
|
|
Help: "The statics info for orm operation",
|
|
|
|
}, []string{"method", "name", "duration", "insideTx", "txName"})
|
|
|
|
|
2020-08-18 14:31:06 +00:00
|
|
|
return func(ctx context.Context, inv *orm.Invocation) []interface{} {
|
2020-08-07 14:14:07 +00:00
|
|
|
startTime := time.Now()
|
2020-08-18 14:31:06 +00:00
|
|
|
res := next(ctx, inv)
|
2020-08-07 14:14:07 +00:00
|
|
|
endTime := time.Now()
|
|
|
|
dur := (endTime.Sub(startTime)) / time.Millisecond
|
|
|
|
|
|
|
|
// if the TPS is too large, here may be some problem
|
|
|
|
// thinking about using goroutine pool
|
|
|
|
go builder.report(ctx, inv, dur)
|
2020-08-18 14:31:06 +00:00
|
|
|
return res
|
2020-08-07 14:14:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (builder *FilterChainBuilder) report(ctx context.Context, inv *orm.Invocation, dur time.Duration) {
|
|
|
|
// start a transaction, we don't record it
|
|
|
|
if strings.HasPrefix(inv.Method, "Begin") {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if inv.Method == "Commit" || inv.Method == "Rollback" {
|
|
|
|
builder.reportTxn(ctx, inv)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
builder.summaryVec.WithLabelValues(inv.Method, inv.GetTableName(), strconv.Itoa(int(dur)),
|
|
|
|
strconv.FormatBool(inv.InsideTx), inv.TxName)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (builder *FilterChainBuilder) reportTxn(ctx context.Context, inv *orm.Invocation) {
|
|
|
|
dur := time.Now().Sub(inv.TxStartTime) / time.Millisecond
|
|
|
|
builder.summaryVec.WithLabelValues(inv.Method, inv.TxName, strconv.Itoa(int(dur)),
|
|
|
|
strconv.FormatBool(inv.InsideTx), inv.TxName)
|
|
|
|
}
|