Compare commits
No commits in common. "master" and "v1.0.4" have entirely different histories.
48
api.go
48
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"
|
||||||
@ -13,7 +12,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
validate = validator.New()
|
validate = validator.New()
|
||||||
requestLogidGetter = defaultLogidGetter
|
requestLogidGetter = defaultLogidGetter
|
||||||
requestHandlerMapper = map[string]gin.HandlerFunc{}
|
requestHandlerMapper = map[string]Handler{}
|
||||||
errCodeUnknownError = -10000
|
errCodeUnknownError = -10000
|
||||||
errCodeParameterError = -20000
|
errCodeParameterError = -20000
|
||||||
errCodeUnimplementApi = -20401
|
errCodeUnimplementApi = -20401
|
||||||
@ -38,12 +37,9 @@ type BaseWithErrCodeOutput struct {
|
|||||||
ErrMsg string `json:"errMsg"`
|
ErrMsg string `json:"errMsg"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEngine(pre ...gin.HandlerFunc) *Engine {
|
func NewEngine() *Engine {
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
e := gin.New()
|
e := gin.New()
|
||||||
for _, m := range pre {
|
|
||||||
e.Use(m)
|
|
||||||
}
|
|
||||||
e.Use(middlewareMyApiEngine())
|
e.Use(middlewareMyApiEngine())
|
||||||
return &Engine{e}
|
return &Engine{e}
|
||||||
}
|
}
|
||||||
@ -54,16 +50,10 @@ func (e *Engine) POST(uri string, handler Handler) {
|
|||||||
e.Engine.POST(uri, h)
|
e.Engine.POST(uri, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) GET(uri string, handler Handler) {
|
|
||||||
h := handlerWrapper(handler)
|
|
||||||
log.Infof("api handler [%v] registor success", handler)
|
|
||||||
e.Engine.GET(uri, h)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handlerWrapper
|
// handlerWrapper
|
||||||
func handlerWrapper(handler Handler) gin.HandlerFunc {
|
func handlerWrapper(handler Handler) gin.HandlerFunc {
|
||||||
handlerFunc := handler.HandlerFunc()
|
handlerFunc := handler.HandlerFunc()
|
||||||
wrappedHandlerFunc := func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
// Case 1. get request handler
|
// Case 1. get request handler
|
||||||
if c.Request == nil && c.Keys != nil {
|
if c.Request == nil && c.Keys != nil {
|
||||||
c.Keys["handler"] = handler
|
c.Keys["handler"] = handler
|
||||||
@ -85,9 +75,6 @@ func handlerWrapper(handler Handler) gin.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hkey := fmt.Sprintf("%v", wrappedHandlerFunc)
|
|
||||||
requestHandlerMapper[hkey] = wrappedHandlerFunc
|
|
||||||
return wrappedHandlerFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handlerWrapper
|
// handlerWrapper
|
||||||
@ -124,9 +111,6 @@ func middlewareMyApiEngine() gin.HandlerFunc {
|
|||||||
|
|
||||||
// Step 3. do request
|
// Step 3. do request
|
||||||
c.Next()
|
c.Next()
|
||||||
|
|
||||||
// Step 4. recorde metrics
|
|
||||||
cc.recordMetrics()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,32 +138,12 @@ func CC(c *gin.Context) *Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ApiHandler(c *gin.Context) Handler {
|
func ApiHandler(c *gin.Context) Handler {
|
||||||
h := c.Handler()
|
newc := &gin.Context{Request: nil, Keys: map[string]any{}}
|
||||||
hkey := fmt.Sprintf("%v", h)
|
c.Handler()(newc)
|
||||||
if _, ok := requestHandlerMapper[hkey]; !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
newc := &gin.Context{
|
|
||||||
Request: nil,
|
|
||||||
Keys: map[string]any{},
|
|
||||||
}
|
|
||||||
h(newc)
|
|
||||||
return newc.Keys["handler"].(Handler)
|
return newc.Keys["handler"].(Handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RecordMetrics(api, errcode, appid string, costms float64) {
|
func DumpHandler(c *Context) error {
|
||||||
var (
|
|
||||||
counter = metricApiCounter.WithLabelValues(api, errcode, appid)
|
|
||||||
summary = metricApiSummary.WithLabelValues(api, errcode, appid)
|
|
||||||
)
|
|
||||||
// Metric 1. api request counter
|
|
||||||
counter.Inc()
|
|
||||||
// Metric 2. api request cost/latency
|
|
||||||
summary.Observe(costms)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DumpHandlerFunc(c *Context) error {
|
|
||||||
errmsg := "api not implemented"
|
errmsg := "api not implemented"
|
||||||
errcode := errCodeUnimplementApi
|
errcode := errCodeUnimplementApi
|
||||||
return c.RESULT_ERROR(errcode, errmsg)
|
return c.RESULT_ERROR(errcode, errmsg)
|
||||||
|
25
context.go
25
context.go
@ -120,14 +120,7 @@ func (c *Context) SetCookie(cookie *http.Cookie) {
|
|||||||
http.SetCookie(c.Writer, cookie)
|
http.SetCookie(c.Writer, cookie)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) AlreadyHaveResult() (done bool, entry string) {
|
|
||||||
return c.resultentry != "", c.resultentry
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Context) RESULT(output interface{}) error {
|
func (c *Context) RESULT(output interface{}) error {
|
||||||
if c.resultentry == "" {
|
|
||||||
c.resultentry = "RESULT"
|
|
||||||
}
|
|
||||||
var t = reflect.TypeOf(output)
|
var t = reflect.TypeOf(output)
|
||||||
defer func(o *interface{}) {
|
defer func(o *interface{}) {
|
||||||
b, err := json.Marshal(o)
|
b, err := json.Marshal(o)
|
||||||
@ -156,6 +149,9 @@ 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 {
|
if _, ok := t.FieldByName("ErrCode"); !ok {
|
||||||
@ -219,21 +215,24 @@ func (c *Context) shapeOutput(o interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) recordMetrics() {
|
func (c *Context) recordMetric() {
|
||||||
if metricApiCounter == nil ||
|
if metricApiCounter == nil ||
|
||||||
metricApiSummary == nil {
|
metricApiSummary == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var h = c.ApiHandler()
|
|
||||||
if h == nil {
|
|
||||||
h = unimplementHandler{c.Context}
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
|
h = c.ApiHandler()
|
||||||
api = h.ApiName()
|
api = h.ApiName()
|
||||||
appid = c.AppId
|
appid = c.AppId
|
||||||
costus = time.Now().Sub(c.starttime).Microseconds()
|
costus = time.Now().Sub(c.starttime).Microseconds()
|
||||||
costms = float64(costus) / 1000.0
|
costms = float64(costus) / 1000.0
|
||||||
errcode = strconv.Itoa(c.errcode)
|
errcode = strconv.Itoa(c.errcode)
|
||||||
|
counter = metricApiCounter.WithLabelValues(api, errcode, appid)
|
||||||
|
summary = metricApiSummary.WithLabelValues(api, errcode, appid)
|
||||||
)
|
)
|
||||||
RecordMetrics(api, errcode, appid, costms)
|
|
||||||
|
// Metric 1. api request counter
|
||||||
|
counter.Inc()
|
||||||
|
// Metric 2. api request cost/latency
|
||||||
|
summary.Observe(costms)
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,20 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"github.com/prometheus/client_golang/prometheus/push"
|
"github.com/prometheus/client_golang/prometheus/push"
|
||||||
"qoobing.com/gomod/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
MetricExporterPusher = func() error { return nil }
|
MetricExporterPusher = func() {}
|
||||||
MetricExporterHandler Handler = nil
|
MetricExporterHandler Handler = nil
|
||||||
MetricRegistry *prometheus.Registry = nil
|
metricRegistry *prometheus.Registry = nil
|
||||||
metricApiCounter *prometheus.CounterVec = nil
|
metricApiCounter *prometheus.CounterVec = nil
|
||||||
metricApiSummary *prometheus.SummaryVec = nil
|
metricApiSummary *prometheus.SummaryVec = nil
|
||||||
instance string = "--unknown--"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type metricExporterHandler struct {
|
type metricExporterHandler struct {
|
||||||
@ -37,24 +33,11 @@ func (m *metricExporterHandler) HandlerFunc() HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpMetricExporterPusher() error {
|
func InitMetrics() {
|
||||||
return errors.New("not initilized, forgot call 'SetupMetricsExporterPusher'?")
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitMetrics(instanceValue string) {
|
|
||||||
if instanceValue == "" {
|
|
||||||
instance = getInstanceIpAddress()
|
|
||||||
} else if ap := strings.Split(instanceValue, ":"); len(ap) == 2 &&
|
|
||||||
ap[0] == "0.0.0.0" || ap[0] == "" {
|
|
||||||
instance = getInstanceIpAddress() + ":" + ap[1]
|
|
||||||
}
|
|
||||||
log.Infof("self instance: [%s]", instance)
|
|
||||||
|
|
||||||
metricApiCounter = prometheus.NewCounterVec(
|
metricApiCounter = prometheus.NewCounterVec(
|
||||||
prometheus.CounterOpts{
|
prometheus.CounterOpts{
|
||||||
Name: "api_requests_total",
|
Name: "api_requests_total",
|
||||||
Help: "How many HTTP requests processed",
|
Help: "How many HTTP requests processed",
|
||||||
//ConstLabels: prometheus.Labels{"instance": instance},
|
|
||||||
},
|
},
|
||||||
[]string{"api", "errcode", "appid"},
|
[]string{"api", "errcode", "appid"},
|
||||||
)
|
)
|
||||||
@ -63,14 +46,12 @@ func InitMetrics(instanceValue string) {
|
|||||||
Name: "api_requests_summary",
|
Name: "api_requests_summary",
|
||||||
Help: "The api request summary of cost.",
|
Help: "The api request summary of cost.",
|
||||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||||
//ConstLabels: prometheus.Labels{"instance": instance},
|
|
||||||
},
|
},
|
||||||
[]string{"api", "errcode", "appid"},
|
[]string{"api", "errcode", "appid"},
|
||||||
)
|
)
|
||||||
|
metricRegistry = prometheus.NewRegistry()
|
||||||
MetricRegistry = prometheus.NewRegistry()
|
metricRegistry.MustRegister(metricApiCounter)
|
||||||
MetricRegistry.MustRegister(metricApiCounter)
|
metricRegistry.MustRegister(metricApiSummary)
|
||||||
MetricRegistry.MustRegister(metricApiSummary)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupMetricsExporterHandler(apiname string) {
|
func SetupMetricsExporterHandler(apiname string) {
|
||||||
@ -78,10 +59,10 @@ func SetupMetricsExporterHandler(apiname string) {
|
|||||||
apiname = "premetheus_metrics_exporter"
|
apiname = "premetheus_metrics_exporter"
|
||||||
}
|
}
|
||||||
|
|
||||||
opt := promhttp.HandlerOpts{Registry: MetricRegistry}
|
opt := promhttp.HandlerOpts{Registry: metricRegistry}
|
||||||
MetricExporterHandler = &metricExporterHandler{
|
MetricExporterHandler = &metricExporterHandler{
|
||||||
name: apiname,
|
name: apiname,
|
||||||
promhttpHandler: promhttp.HandlerFor(MetricRegistry, opt),
|
promhttpHandler: promhttp.HandlerFor(metricRegistry, opt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,13 +71,8 @@ func SetupMetricsExporterPusher(pushgateway string, jobname string) {
|
|||||||
jobname = fmt.Sprintf("api-metrics-job-%s", getExeFilename())
|
jobname = fmt.Sprintf("api-metrics-job-%s", getExeFilename())
|
||||||
}
|
}
|
||||||
|
|
||||||
var pusher = push.
|
var pusher = push.New(pushgateway, jobname).Gatherer(metricRegistry)
|
||||||
New(pushgateway, jobname).
|
MetricExporterPusher = func() {
|
||||||
Grouping("instance", instance).
|
pusher.Push()
|
||||||
Gatherer(MetricRegistry)
|
|
||||||
|
|
||||||
MetricExporterPusher = func() error {
|
|
||||||
RecordMetrics("push_metrics_to_prometheus", "0", "selfmonitoring", 1.0)
|
|
||||||
return pusher.Push()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
routes.go
21
routes.go
@ -1,12 +1,5 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ///////////////////////////////////////////////////////////////////
|
// ///////////////////////////////////////////////////////////////////
|
||||||
// IRouter & IRoutes in gin, we redefine it simple
|
// IRouter & IRoutes in gin, we redefine it simple
|
||||||
// ///////////////////////////////////////////////////////////////////
|
// ///////////////////////////////////////////////////////////////////
|
||||||
@ -47,19 +40,5 @@ type Handler interface {
|
|||||||
type HandlerFunc func(*Context) error
|
type HandlerFunc func(*Context) error
|
||||||
|
|
||||||
type IRoutes interface {
|
type IRoutes interface {
|
||||||
GET(uri string, handler Handler)
|
|
||||||
POST(uri string, handler Handler)
|
POST(uri string, handler Handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
type unimplementHandler struct {
|
|
||||||
c *gin.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u unimplementHandler) ApiName() string {
|
|
||||||
req := u.c.Request
|
|
||||||
return strings.ToLower(fmt.Sprintf("[%s]%s", req.Method, req.RequestURI))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u unimplementHandler) HandlerFunc() HandlerFunc {
|
|
||||||
return DumpHandlerFunc
|
|
||||||
}
|
|
||||||
|
55
util.go
55
util.go
@ -1,11 +1,8 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// getExeFilename
|
// getExeFilename
|
||||||
@ -16,55 +13,3 @@ func getExeFilename() string {
|
|||||||
}
|
}
|
||||||
return logfilename
|
return logfilename
|
||||||
}
|
}
|
||||||
|
|
||||||
// preferencesMatch
|
|
||||||
func preferencesMatch(s string, preferences ...string) bool {
|
|
||||||
for _, pstr := range preferences {
|
|
||||||
reg := regexp.MustCompile(pstr)
|
|
||||||
if reg.Match([]byte(s)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// getInstanceIpAddress
|
|
||||||
func getInstanceIpAddress(preferences ...string) string {
|
|
||||||
addrs, err := net.InterfaceAddrs()
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("getInstanceIpAddress failed: [%s]", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
prefer := func() func(string) bool {
|
|
||||||
if len(preferences) <= 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return func(ip string) bool {
|
|
||||||
return preferencesMatch(ip, preferences...)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
var ipnets = []*net.IPNet{}
|
|
||||||
for _, address := range addrs {
|
|
||||||
if ipnet, ok := address.(*net.IPNet); !ok {
|
|
||||||
continue
|
|
||||||
} else if ipnet.IP.IsLoopback() {
|
|
||||||
continue
|
|
||||||
} else if ipv4 := ipnet.IP.To4(); ipv4 == nil {
|
|
||||||
continue
|
|
||||||
} else if prefer == nil {
|
|
||||||
var n = *ipnet
|
|
||||||
ipnets = append(ipnets, &n)
|
|
||||||
continue
|
|
||||||
} else if prefer != nil && prefer(ipv4.String()) {
|
|
||||||
return ipv4.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: sort & return first
|
|
||||||
if len(ipnets) > 0 {
|
|
||||||
return ipnets[0].IP.To4().String()
|
|
||||||
}
|
|
||||||
panic(fmt.Sprintf("getInstanceIpAddreass failed,"+
|
|
||||||
"preferences=[%v], ipnets=[%v]", preferences, ipnets))
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user