feat: docs api design

This commit is contained in:
neo-f
2023-03-22 22:45:17 +08:00
commit 084d0de8bc
52 changed files with 3420 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
package metrics
import "github.com/gofiber/fiber/v2"
// Config defines the config for middleware.
type Config struct {
// Next defines a function to skip this middleware when returned true.
//
// Optional. Default: nil
Next func(c *fiber.Ctx) bool
}
// ConfigDefault is the default config
var ConfigDefault = Config{
Next: nil,
}
// Helper function to set default values
func configDefault(config ...Config) Config {
// Return default config if nothing provided
if len(config) < 1 {
return ConfigDefault
}
// Override default config
cfg := config[0]
return cfg
}

View File

@@ -0,0 +1,135 @@
package metrics
import (
"strconv"
"time"
"github.com/gofiber/fiber/v2"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
const serviceName = "cp-service"
var (
labels = prometheus.Labels{"service": serviceName}
KafkaConsumeSuccessCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: prometheus.BuildFQName("cp", "kafka", "consume_success"),
Help: "记录kafka消息消费成功的次数",
ConstLabels: labels,
}, []string{"topic", "bid"},
)
KafkaConsumeErrorCounter = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: prometheus.BuildFQName("cp", "kafka", "consume_error"),
Help: "记录kafka消息消费失败的次数",
ConstLabels: labels,
}, []string{"topic", "bid"},
)
KafkaConsumeProcessingCounter = promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: prometheus.BuildFQName("cp", "kafka", "consume_processing"),
Help: "当前正在处理的kafka消息个数",
ConstLabels: labels,
}, []string{"topic", "bid"},
)
requestInProgressTotal = promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: prometheus.BuildFQName("cp", "http", "requests_in_progress_total"),
Help: "All the requests in progress",
ConstLabels: labels,
}, []string{"method"})
requestsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
Name: prometheus.BuildFQName("cp", "http", "requests_total"),
Help: "Count all http requests by status code, method and path.",
ConstLabels: labels,
},
[]string{"status_code", "method", "path"},
)
requestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
Name: prometheus.BuildFQName("cp", "http", "request_duration_seconds"),
Help: "Duration of all HTTP requests by status code, method and path.",
ConstLabels: labels,
Buckets: []float64{
0.000000001, // 1ns
0.000000002,
0.000000005,
0.00000001, // 10ns
0.00000002,
0.00000005,
0.0000001, // 100ns
0.0000002,
0.0000005,
0.000001, // 1µs
0.000002,
0.000005,
0.00001, // 10µs
0.00002,
0.00005,
0.0001, // 100µs
0.0002,
0.0005,
0.001, // 1ms
0.002,
0.005,
0.01, // 10ms
0.02,
0.05,
0.1, // 100 ms
0.2,
0.5,
1.0, // 1s
2.0,
5.0,
10.0, // 10s
15.0,
20.0,
30.0,
},
},
[]string{"status_code", "method", "path"},
)
)
func NewMiddleware(cfgs ...Config) fiber.Handler {
cfg := configDefault(cfgs...)
return func(ctx *fiber.Ctx) error {
if cfg.Next != nil && cfg.Next(ctx) {
return ctx.Next()
}
start := time.Now()
method := ctx.Route().Method
if ctx.Route().Path == "/metrics" {
return ctx.Next()
}
requestInProgressTotal.WithLabelValues(method).Inc()
defer requestInProgressTotal.WithLabelValues(method).Dec()
err := ctx.Next()
// initialize with default error code
// https://docs.gofiber.io/guide/error-handling
status := fiber.StatusInternalServerError
if err != nil {
if e, ok := err.(*fiber.Error); ok {
// Get correct error code from fiber.Error type
status = e.Code
}
} else {
status = ctx.Response().StatusCode()
}
path := ctx.Route().Path
statusCode := strconv.Itoa(status)
requestsTotal.WithLabelValues(statusCode, method, path).Inc()
elapsed := float64(time.Since(start).Nanoseconds()) / 1e9
requestDuration.WithLabelValues(statusCode, method, path).Observe(elapsed)
return err
}
}

View File

@@ -0,0 +1,60 @@
package uniform
import (
"github.com/gofiber/fiber/v2"
"github.com/rs/zerolog/log"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
)
// 调整JSON结果返回为公司要求的统一格式
// New creates a new middleware handler
func New(cfgs ...Config) fiber.Handler {
// Set default config
cfg := configDefault(cfgs...)
// Return new handler
return func(ctx *fiber.Ctx) error {
// Don't execute middleware if Next returns true
if cfg.Next != nil && cfg.Next(ctx) {
return ctx.Next()
}
uniformedResp := []byte{}
_ = ctx.Next()
code := ctx.Response().StatusCode()
if code >= 200 && code < 300 {
if string(ctx.Response().Header.ContentType()) == "application/json" {
uniformedResp, _ = sjson.SetBytes(uniformedResp, "code", 0)
uniformedResp, _ = sjson.SetRawBytes(uniformedResp, "data", ctx.Response().Body())
ctx.Response().SetBodyRaw(uniformedResp)
}
return nil
}
if code == 422 {
uniformedResp, _ = sjson.SetBytes(uniformedResp, "code", 422)
uniformedResp, _ = sjson.SetBytes(uniformedResp, "message", "参数校验失败")
uniformedResp, _ = sjson.SetRawBytes(uniformedResp, "details", ctx.Response().Body())
ctx.Response().SetBodyRaw(uniformedResp)
return nil
}
if code >= 400 {
log.Ctx(ctx.UserContext()).Error().
Int("status", code).
Str("request", ctx.String()).
Bytes("body", uniformedResp).
Msg("error occurred")
uniformedResp, _ = sjson.SetBytes(uniformedResp, "code", code)
resp := ctx.Context().Response.Body()
if msg := gjson.GetBytes(resp, "message"); msg.Exists() {
uniformedResp, _ = sjson.SetBytes(uniformedResp, "message", msg.String())
} else {
uniformedResp, _ = sjson.SetBytes(uniformedResp, "message", resp)
}
ctx.Response().SetBodyRaw(uniformedResp)
}
return nil
}
}

View File

@@ -0,0 +1,29 @@
package uniform
import "github.com/gofiber/fiber/v2"
// Config defines the config for middleware.
type Config struct {
// Next defines a function to skip this middleware when returned true.
//
// Optional. Default: nil
Next func(c *fiber.Ctx) bool
}
// ConfigDefault is the default config
var ConfigDefault = Config{
Next: nil,
}
// Helper function to set default values
func configDefault(config ...Config) Config {
// Return default config if nothing provided
if len(config) < 1 {
return ConfigDefault
}
// Override default config
cfg := config[0]
return cfg
}