add prometheus
This commit is contained in:
parent
92b821a12d
commit
900d2e9789
6
api.go
6
api.go
@ -13,7 +13,7 @@ import (
|
||||
var (
|
||||
validate = validator.New()
|
||||
requestLogidGetter = defaultLogidGetter
|
||||
handlerMapper = map[string]Handler{}
|
||||
requestHandlerMapper = map[string]Handler{}
|
||||
errCodeUnknownError = -10000
|
||||
errCodeParameterError = -20000
|
||||
errCodeUnimplementApi = -20401
|
||||
@ -47,7 +47,9 @@ func NewEngine() *Engine {
|
||||
|
||||
func (e *Engine) POST(uri string, handler Handler) {
|
||||
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)
|
||||
}
|
||||
|
||||
|
92
context.go
92
context.go
@ -26,6 +26,7 @@ type Context struct {
|
||||
httpstatus int
|
||||
starttime time.Time
|
||||
output interface{}
|
||||
errcode int
|
||||
}
|
||||
|
||||
func New(c *gin.Context) *Context {
|
||||
@ -146,28 +147,62 @@ func (c *Context) RESULT(output interface{}) error {
|
||||
cost := time.Now().Sub(c.starttime).Milliseconds()
|
||||
noticeStr := fmt.Sprintf("cost: %dms, output: '%s'", cost, string(b))
|
||||
log.NoticefWithDepth(calldepth, noticeStr)
|
||||
|
||||
//// metric ////////////////////////////////////////
|
||||
c.recordMetric()
|
||||
}(&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 {
|
||||
errstr := "Result MUST have 'ErrMsg' field"
|
||||
output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
|
||||
c.ShapeOutput(output)
|
||||
c.shapeOutput(output)
|
||||
c.errcode = reflect.ValueOf(output).FieldByName("ErrCode").GetInt()
|
||||
c.IndentedJSON(c.httpstatus, output)
|
||||
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)
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -183,26 +218,23 @@ func (c *Context) ShapeOutput(o interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Context) ApiHandler() Handler {
|
||||
h := c.Context.Handler()
|
||||
if handler, ok := handlerMapper[fmt.Sprintf("%v", h)]; ok {
|
||||
return handler
|
||||
}
|
||||
return nil
|
||||
func (c *Context) recordMetric() {
|
||||
if metricApiCounter == nil ||
|
||||
metricApiSummary == nil {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
if c.resultentry == "" {
|
||||
c.resultentry = "RESULT_ERROR"
|
||||
}
|
||||
|
||||
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)
|
||||
// Metric 1. api request counter
|
||||
counter.Inc()
|
||||
// Metric 2. api request cost/latency
|
||||
summary.Observe(cost)
|
||||
}
|
||||
|
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 {
|
||||
Name() string
|
||||
HandlerFunc() HandlerFunc
|
||||
}
|
||||
type HandlerFunc func(*Context) error
|
||||
|
Loading…
Reference in New Issue
Block a user