add prometheus record
This commit is contained in:
parent
900d2e9789
commit
8335b17e89
44
api.go
44
api.go
@ -1,7 +1,6 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -46,15 +45,40 @@ func NewEngine() *Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) POST(uri string, handler Handler) {
|
func (e *Engine) POST(uri string, handler Handler) {
|
||||||
h := handlerWrapper(handler.HandlerFunc())
|
h := handlerWrapper(handler)
|
||||||
hkey := fmt.Sprintf("%v", h)
|
log.Infof("api handler [%v] registor success", handler)
|
||||||
requestHandlerMapper[hkey] = handler
|
|
||||||
log.Infof("api handler [%s] registor success", hkey)
|
|
||||||
e.Engine.POST(uri, h)
|
e.Engine.POST(uri, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handlerWrapper
|
// handlerWrapper
|
||||||
func handlerWrapper(handler HandlerFunc) gin.HandlerFunc {
|
func handlerWrapper(handler Handler) gin.HandlerFunc {
|
||||||
|
handlerFunc := handler.HandlerFunc()
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
// Case 1. get request handler
|
||||||
|
if c.Request == nil && c.Keys != nil {
|
||||||
|
c.Keys["handler"] = handler
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2. normal case, user request will go this way
|
||||||
|
if icc, ok := c.Get("cc"); !ok {
|
||||||
|
log.Errorf("Unreachable Code: can not get cc(*api.Context) from *gin.Context")
|
||||||
|
} else if cc, ok := icc.(*Context); !ok {
|
||||||
|
log.Debugf("Unreachable Code: cc from *gin.Context is type of:[%s]", reflect.TypeOf(icc).String())
|
||||||
|
log.Errorf("Unreachable Code: cc from *gin.Context is not type of *api.Context")
|
||||||
|
} else {
|
||||||
|
// user request should go this way
|
||||||
|
defer cc.TryRecover()
|
||||||
|
cc.AppId = c.GetString("appid")
|
||||||
|
cc.UserId = c.GetUint64("userid")
|
||||||
|
handlerFunc(cc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handlerWrapper
|
||||||
|
func handlerFuncWrapper(handler HandlerFunc) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
if icc, ok := c.Get("cc"); !ok {
|
if icc, ok := c.Get("cc"); !ok {
|
||||||
log.Errorf("Unreachable Code: can not get cc(*api.Context) from *gin.Context")
|
log.Errorf("Unreachable Code: can not get cc(*api.Context) from *gin.Context")
|
||||||
@ -66,6 +90,7 @@ func handlerWrapper(handler HandlerFunc) gin.HandlerFunc {
|
|||||||
cc.AppId = c.GetString("appid")
|
cc.AppId = c.GetString("appid")
|
||||||
cc.UserId = c.GetUint64("userid")
|
cc.UserId = c.GetUint64("userid")
|
||||||
handler(cc)
|
handler(cc)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,8 +138,9 @@ func CC(c *gin.Context) *Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ApiHandler(c *gin.Context) Handler {
|
func ApiHandler(c *gin.Context) Handler {
|
||||||
cc := CC(c)
|
newc := &gin.Context{Request: nil, Keys: map[string]any{}}
|
||||||
return cc.ApiHandler()
|
c.Handler()(newc)
|
||||||
|
return newc.Keys["handler"].(Handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DumpHandler(c *Context) error {
|
func DumpHandler(c *Context) error {
|
||||||
@ -124,7 +150,7 @@ func DumpHandler(c *Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ErrorHandler(c *gin.Context, errcode int, errmsg string) {
|
func ErrorHandler(c *gin.Context, errcode int, errmsg string) {
|
||||||
handler := handlerWrapper(func(c *Context) error {
|
handler := handlerFuncWrapper(func(c *Context) error {
|
||||||
return c.RESULT_ERROR(errcode, errmsg)
|
return c.RESULT_ERROR(errcode, errmsg)
|
||||||
})
|
})
|
||||||
handler(c)
|
handler(c)
|
||||||
|
40
context.go
40
context.go
@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ import (
|
|||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
*gin.Context
|
*gin.Context
|
||||||
|
e *gin.Engine
|
||||||
|
|
||||||
AppId string //current request appid, must not be empty
|
AppId string //current request appid, must not be empty
|
||||||
UserId uint64 //current request userid, maybe 0 if user unknown
|
UserId uint64 //current request userid, maybe 0 if user unknown
|
||||||
@ -152,25 +154,26 @@ func (c *Context) RESULT(output interface{}) error {
|
|||||||
c.recordMetric()
|
c.recordMetric()
|
||||||
}(&output)
|
}(&output)
|
||||||
|
|
||||||
if _, ok := t.FieldByName("ErrMsg"); !ok {
|
|
||||||
errstr := "Result MUST have 'ErrMsg' field"
|
|
||||||
output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
|
|
||||||
c.shapeOutput(output)
|
|
||||||
c.errcode = reflect.ValueOf(output).FieldByName("ErrCode").GetInt()
|
|
||||||
c.IndentedJSON(c.httpstatus, output)
|
|
||||||
return errors.New(errstr)
|
|
||||||
}
|
|
||||||
if _, ok := t.FieldByName("ErrCode"); !ok {
|
if _, ok := t.FieldByName("ErrCode"); !ok {
|
||||||
errstr := "Result MUST have 'ErrCode' field"
|
errstr := "Result MUST have 'ErrCode' field"
|
||||||
output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
|
output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
|
||||||
c.shapeOutput(output)
|
c.shapeOutput(output)
|
||||||
c.errcode = reflect.ValueOf(output).FieldByName("ErrCode").GetInt()
|
c.errcode = int(reflect.ValueOf(output).FieldByName("ErrCode").Int())
|
||||||
|
c.IndentedJSON(c.httpstatus, output)
|
||||||
|
return errors.New(errstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := t.FieldByName("ErrMsg"); !ok {
|
||||||
|
errstr := "Result MUST have 'ErrMsg' field"
|
||||||
|
output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
|
||||||
|
c.shapeOutput(output)
|
||||||
|
c.errcode = int(reflect.ValueOf(output).FieldByName("ErrCode").Int())
|
||||||
c.IndentedJSON(c.httpstatus, output)
|
c.IndentedJSON(c.httpstatus, output)
|
||||||
return errors.New(errstr)
|
return errors.New(errstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.shapeOutput(output)
|
c.shapeOutput(output)
|
||||||
c.errcode = reflect.ValueOf(output).FieldByName("ErrCode").GetInt()
|
c.errcode = int(reflect.ValueOf(output).FieldByName("ErrCode").Int())
|
||||||
c.IndentedJSON(c.httpstatus, output)
|
c.IndentedJSON(c.httpstatus, output)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -193,13 +196,7 @@ func (c *Context) RESULT_PARAMETER_ERROR(err string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) ApiHandler() Handler {
|
func (c *Context) ApiHandler() Handler {
|
||||||
h := c.Context.Handler()
|
return ApiHandler(c.Context)
|
||||||
hkey := fmt.Sprintf("%v", h)
|
|
||||||
if handler, ok := requestHandlerMapper[hkey]; ok {
|
|
||||||
return handler
|
|
||||||
}
|
|
||||||
log.Fatalf("api handler [%s] not found", hkey)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) shapeOutput(o interface{}) {
|
func (c *Context) shapeOutput(o interface{}) {
|
||||||
@ -225,10 +222,11 @@ func (c *Context) recordMetric() {
|
|||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
h = c.ApiHandler()
|
h = c.ApiHandler()
|
||||||
api = h.Name()
|
api = h.ApiName()
|
||||||
cost = time.Now().Sub(c.starttime).Milliseconds()
|
|
||||||
appid = c.AppId
|
appid = c.AppId
|
||||||
errcode = c.errcode
|
costus = time.Now().Sub(c.starttime).Microseconds()
|
||||||
|
costms = float64(costus) / 1000.0
|
||||||
|
errcode = strconv.Itoa(c.errcode)
|
||||||
counter = metricApiCounter.WithLabelValues(api, errcode, appid)
|
counter = metricApiCounter.WithLabelValues(api, errcode, appid)
|
||||||
summary = metricApiSummary.WithLabelValues(api, errcode, appid)
|
summary = metricApiSummary.WithLabelValues(api, errcode, appid)
|
||||||
)
|
)
|
||||||
@ -236,5 +234,5 @@ func (c *Context) recordMetric() {
|
|||||||
// Metric 1. api request counter
|
// Metric 1. api request counter
|
||||||
counter.Inc()
|
counter.Inc()
|
||||||
// Metric 2. api request cost/latency
|
// Metric 2. api request cost/latency
|
||||||
summary.Observe(cost)
|
summary.Observe(costms)
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,13 @@ type metricExporterHandler struct {
|
|||||||
promhttpHandler http.Handler
|
promhttpHandler http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *metricExporterHandler) Name() string {
|
func (m *metricExporterHandler) ApiName() string {
|
||||||
return m.apiName
|
return m.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *metricExporterHandler) HandlerFunc() HandlerFunc {
|
func (m *metricExporterHandler) HandlerFunc() HandlerFunc {
|
||||||
return func(c *Context) (err error) {
|
return func(c *Context) (err error) {
|
||||||
m.promhttpHandler.ServeHTTP(c.ResponseWriter, c.Request)
|
m.promhttpHandler.ServeHTTP(c.Writer, c.Request)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,8 +50,6 @@ func InitMetrics() {
|
|||||||
[]string{"api", "errcode", "appid"},
|
[]string{"api", "errcode", "appid"},
|
||||||
)
|
)
|
||||||
metricRegistry = prometheus.NewRegistry()
|
metricRegistry = prometheus.NewRegistry()
|
||||||
|
|
||||||
opt := promhttp.HandlerOpts{Registry: metricRegistry}
|
|
||||||
metricRegistry.MustRegister(metricApiCounter)
|
metricRegistry.MustRegister(metricApiCounter)
|
||||||
metricRegistry.MustRegister(metricApiSummary)
|
metricRegistry.MustRegister(metricApiSummary)
|
||||||
}
|
}
|
||||||
@ -61,6 +59,7 @@ func SetupMetricsExporterHandler(apiname string) {
|
|||||||
apiname = "premetheus_metrics_exporter"
|
apiname = "premetheus_metrics_exporter"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opt := promhttp.HandlerOpts{Registry: metricRegistry}
|
||||||
MetricExporterHandler = &metricExporterHandler{
|
MetricExporterHandler = &metricExporterHandler{
|
||||||
name: apiname,
|
name: apiname,
|
||||||
promhttpHandler: promhttp.HandlerFor(metricRegistry, opt),
|
promhttpHandler: promhttp.HandlerFor(metricRegistry, opt),
|
||||||
|
@ -34,7 +34,7 @@ package api
|
|||||||
// ///////////////////////////////////////////////////////////////////
|
// ///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
Name() string
|
ApiName() string
|
||||||
HandlerFunc() HandlerFunc
|
HandlerFunc() HandlerFunc
|
||||||
}
|
}
|
||||||
type HandlerFunc func(*Context) error
|
type HandlerFunc func(*Context) error
|
||||||
|
Loading…
Reference in New Issue
Block a user