add prometheus
This commit is contained in:
parent
92b821a12d
commit
900d2e9789
6
api.go
6
api.go
@ -13,7 +13,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
validate = validator.New()
|
validate = validator.New()
|
||||||
requestLogidGetter = defaultLogidGetter
|
requestLogidGetter = defaultLogidGetter
|
||||||
handlerMapper = map[string]Handler{}
|
requestHandlerMapper = map[string]Handler{}
|
||||||
errCodeUnknownError = -10000
|
errCodeUnknownError = -10000
|
||||||
errCodeParameterError = -20000
|
errCodeParameterError = -20000
|
||||||
errCodeUnimplementApi = -20401
|
errCodeUnimplementApi = -20401
|
||||||
@ -47,7 +47,9 @@ 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.HandlerFunc())
|
||||||
handlerMapper[fmt.Sprintf("%v", h)] = handler
|
hkey := fmt.Sprintf("%v", h)
|
||||||
|
requestHandlerMapper[hkey] = handler
|
||||||
|
log.Infof("api handler [%s] registor success", hkey)
|
||||||
e.Engine.POST(uri, h)
|
e.Engine.POST(uri, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
92
context.go
92
context.go
@ -26,6 +26,7 @@ type Context struct {
|
|||||||
httpstatus int
|
httpstatus int
|
||||||
starttime time.Time
|
starttime time.Time
|
||||||
output interface{}
|
output interface{}
|
||||||
|
errcode int
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(c *gin.Context) *Context {
|
func New(c *gin.Context) *Context {
|
||||||
@ -146,28 +147,62 @@ func (c *Context) RESULT(output interface{}) error {
|
|||||||
cost := time.Now().Sub(c.starttime).Milliseconds()
|
cost := time.Now().Sub(c.starttime).Milliseconds()
|
||||||
noticeStr := fmt.Sprintf("cost: %dms, output: '%s'", cost, string(b))
|
noticeStr := fmt.Sprintf("cost: %dms, output: '%s'", cost, string(b))
|
||||||
log.NoticefWithDepth(calldepth, noticeStr)
|
log.NoticefWithDepth(calldepth, noticeStr)
|
||||||
|
|
||||||
|
//// metric ////////////////////////////////////////
|
||||||
|
c.recordMetric()
|
||||||
}(&output)
|
}(&output)
|
||||||
|
|
||||||
if _, ok := t.FieldByName("ErrCode"); !ok {
|
|
||||||
errstr := "Result MUST have 'ErrCode' field"
|
|
||||||
output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
|
|
||||||
c.ShapeOutput(output)
|
|
||||||
c.IndentedJSON(c.httpstatus, output)
|
|
||||||
return errors.New(errstr)
|
|
||||||
}
|
|
||||||
if _, ok := t.FieldByName("ErrMsg"); !ok {
|
if _, ok := t.FieldByName("ErrMsg"); !ok {
|
||||||
errstr := "Result MUST have 'ErrMsg' field"
|
errstr := "Result MUST have 'ErrMsg' field"
|
||||||
output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
|
output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
|
||||||
c.ShapeOutput(output)
|
c.shapeOutput(output)
|
||||||
|
c.errcode = reflect.ValueOf(output).FieldByName("ErrCode").GetInt()
|
||||||
c.IndentedJSON(c.httpstatus, output)
|
c.IndentedJSON(c.httpstatus, output)
|
||||||
return errors.New(errstr)
|
return errors.New(errstr)
|
||||||
}
|
}
|
||||||
c.ShapeOutput(output)
|
if _, ok := t.FieldByName("ErrCode"); !ok {
|
||||||
|
errstr := "Result MUST have 'ErrCode' 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.shapeOutput(output)
|
||||||
|
c.errcode = reflect.ValueOf(output).FieldByName("ErrCode").GetInt()
|
||||||
c.IndentedJSON(c.httpstatus, output)
|
c.IndentedJSON(c.httpstatus, output)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) ShapeOutput(o interface{}) {
|
func (c *Context) RESULT_ERROR(eno int, err string) error {
|
||||||
|
if c.resultentry == "" {
|
||||||
|
c.resultentry = "RESULT_ERROR"
|
||||||
|
}
|
||||||
|
|
||||||
|
result := BaseWithErrCodeOutput{eno, err}
|
||||||
|
c.errcode = eno
|
||||||
|
return c.RESULT(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) RESULT_PARAMETER_ERROR(err string) error {
|
||||||
|
if c.resultentry == "" {
|
||||||
|
c.resultentry = "RESULT_PARAMETER_ERROR"
|
||||||
|
}
|
||||||
|
return c.RESULT_ERROR(errCodeParameterError, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) ApiHandler() Handler {
|
||||||
|
h := c.Context.Handler()
|
||||||
|
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{}) {
|
||||||
if c.output == nil {
|
if c.output == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -183,26 +218,23 @@ func (c *Context) ShapeOutput(o interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) ApiHandler() Handler {
|
func (c *Context) recordMetric() {
|
||||||
h := c.Context.Handler()
|
if metricApiCounter == nil ||
|
||||||
if handler, ok := handlerMapper[fmt.Sprintf("%v", h)]; ok {
|
metricApiSummary == nil {
|
||||||
return handler
|
return
|
||||||
}
|
}
|
||||||
return nil
|
var (
|
||||||
}
|
h = c.ApiHandler()
|
||||||
|
api = h.Name()
|
||||||
|
cost = time.Now().Sub(c.starttime).Milliseconds()
|
||||||
|
appid = c.AppId
|
||||||
|
errcode = c.errcode
|
||||||
|
counter = metricApiCounter.WithLabelValues(api, errcode, appid)
|
||||||
|
summary = metricApiSummary.WithLabelValues(api, errcode, appid)
|
||||||
|
)
|
||||||
|
|
||||||
func (c *Context) RESULT_ERROR(eno int, err string) error {
|
// Metric 1. api request counter
|
||||||
if c.resultentry == "" {
|
counter.Inc()
|
||||||
c.resultentry = "RESULT_ERROR"
|
// Metric 2. api request cost/latency
|
||||||
}
|
summary.Observe(cost)
|
||||||
|
|
||||||
result := BaseWithErrCodeOutput{eno, err}
|
|
||||||
return c.RESULT(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) RESULT_PARAMETER_ERROR(err string) error {
|
|
||||||
if c.resultentry == "" {
|
|
||||||
c.resultentry = "RESULT_PARAMETER_ERROR"
|
|
||||||
}
|
|
||||||
return c.RESULT_ERROR(errCodeParameterError, err)
|
|
||||||
}
|
}
|
||||||
|
79
prometheus.go
Normal file
79
prometheus.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/push"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
MetricExporterPusher = func() {}
|
||||||
|
MetricExporterHandler Handler = nil
|
||||||
|
metricRegistry *prometheus.Registry = nil
|
||||||
|
metricApiCounter *prometheus.CounterVec = nil
|
||||||
|
metricApiSummary *prometheus.SummaryVec = nil
|
||||||
|
)
|
||||||
|
|
||||||
|
type metricExporterHandler struct {
|
||||||
|
name string
|
||||||
|
promhttpHandler http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricExporterHandler) Name() string {
|
||||||
|
return m.apiName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *metricExporterHandler) HandlerFunc() HandlerFunc {
|
||||||
|
return func(c *Context) (err error) {
|
||||||
|
m.promhttpHandler.ServeHTTP(c.ResponseWriter, c.Request)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitMetrics() {
|
||||||
|
metricApiCounter = prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "api_requests_total",
|
||||||
|
Help: "How many HTTP requests processed",
|
||||||
|
},
|
||||||
|
[]string{"api", "errcode", "appid"},
|
||||||
|
)
|
||||||
|
metricApiSummary = prometheus.NewSummaryVec(
|
||||||
|
prometheus.SummaryOpts{
|
||||||
|
Name: "api_requests_summary",
|
||||||
|
Help: "The api request summary of cost.",
|
||||||
|
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||||
|
},
|
||||||
|
[]string{"api", "errcode", "appid"},
|
||||||
|
)
|
||||||
|
metricRegistry = prometheus.NewRegistry()
|
||||||
|
|
||||||
|
opt := promhttp.HandlerOpts{Registry: metricRegistry}
|
||||||
|
metricRegistry.MustRegister(metricApiCounter)
|
||||||
|
metricRegistry.MustRegister(metricApiSummary)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupMetricsExporterHandler(apiname string) {
|
||||||
|
if apiname == "" {
|
||||||
|
apiname = "premetheus_metrics_exporter"
|
||||||
|
}
|
||||||
|
|
||||||
|
MetricExporterHandler = &metricExporterHandler{
|
||||||
|
name: apiname,
|
||||||
|
promhttpHandler: promhttp.HandlerFor(metricRegistry, opt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupMetricsExporterPusher(pushgateway string, jobname string) {
|
||||||
|
if jobname == "" {
|
||||||
|
jobname = fmt.Sprintf("api-metrics-job-%s", getExeFilename())
|
||||||
|
}
|
||||||
|
|
||||||
|
var pusher = push.New(pushgateway, jobname).Gatherer(metricRegistry)
|
||||||
|
MetricExporterPusher = func() {
|
||||||
|
pusher.Push()
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ package api
|
|||||||
// ///////////////////////////////////////////////////////////////////
|
// ///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
type Handler interface {
|
type Handler interface {
|
||||||
|
Name() string
|
||||||
HandlerFunc() HandlerFunc
|
HandlerFunc() HandlerFunc
|
||||||
}
|
}
|
||||||
type HandlerFunc func(*Context) error
|
type HandlerFunc func(*Context) error
|
||||||
|
Loading…
Reference in New Issue
Block a user