forked from free-lancers/electricity_bill_calc_service
refactor(app):基本完成基础服务框架的功能构建。
This commit is contained in:
@@ -1,48 +1,87 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Logger() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
path := c.Request.URL.Path
|
||||
raw := c.Request.URL.RawQuery
|
||||
// Config defines the config for middleware
|
||||
type LogMiddlewareConfig struct {
|
||||
// Next defines a function to skip this middleware when returned true.
|
||||
//
|
||||
// Optional. Default: nil
|
||||
Next func(c *fiber.Ctx) bool
|
||||
|
||||
// Process request
|
||||
c.Next()
|
||||
// Logger defines zap logger instance
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
latency := time.Since(start)
|
||||
// New creates a new middleware handler
|
||||
func NewLogMiddleware(config LogMiddlewareConfig) fiber.Handler {
|
||||
var (
|
||||
errPadding = 15
|
||||
start, stop time.Time
|
||||
once sync.Once
|
||||
errHandler fiber.ErrorHandler
|
||||
)
|
||||
|
||||
clientIP := c.ClientIP()
|
||||
method := c.Request.Method
|
||||
statusCode := c.Writer.Status()
|
||||
|
||||
comment := c.Errors.ByType(gin.ErrorTypePrivate).String()
|
||||
|
||||
if raw != "" {
|
||||
path = path + "?" + raw
|
||||
return func(c *fiber.Ctx) error {
|
||||
if config.Next != nil && config.Next(c) {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
once.Do(func() {
|
||||
errHandler = c.App().Config().ErrorHandler
|
||||
stack := c.App().Stack()
|
||||
for m := range stack {
|
||||
for r := range stack[m] {
|
||||
if len(stack[m][r].Path) > errPadding {
|
||||
errPadding = len(stack[m][r].Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
start = time.Now()
|
||||
|
||||
chainErr := c.Next()
|
||||
|
||||
if chainErr != nil {
|
||||
if err := errHandler(c, chainErr); err != nil {
|
||||
_ = c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
stop = time.Now()
|
||||
|
||||
fields := []zap.Field{
|
||||
zap.Int("statusCode", statusCode),
|
||||
zap.Duration("latency", latency),
|
||||
zap.String("clientIP", clientIP),
|
||||
zap.String("method", method),
|
||||
zap.String("path", path),
|
||||
zap.Namespace("context"),
|
||||
zap.String("pid", strconv.Itoa(os.Getpid())),
|
||||
zap.String("time", stop.Sub(start).String()),
|
||||
zap.Object("response", Resp(c.Response())),
|
||||
zap.Object("request", Req(c)),
|
||||
}
|
||||
if comment != "" {
|
||||
logger.Named("Gin").Error(
|
||||
comment,
|
||||
fields...,
|
||||
)
|
||||
} else {
|
||||
logger.Named("Gin").Info(fmt.Sprintf("%s -> [%d] %s %s.", clientIP, statusCode, method, path), fields...)
|
||||
|
||||
if u := c.Locals("userId"); u != nil {
|
||||
fields = append(fields, zap.Uint("userId", u.(uint)))
|
||||
}
|
||||
|
||||
formatErr := ""
|
||||
if chainErr != nil {
|
||||
formatErr = chainErr.Error()
|
||||
fields = append(fields, zap.String("error", formatErr))
|
||||
config.Logger.With(fields...).Error(formatErr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
config.Logger.With(fields...).Info("api.request")
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
119
logger/middleware_types.go
Normal file
119
logger/middleware_types.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/valyala/fasthttp"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
func getAllowedHeaders() map[string]bool {
|
||||
return map[string]bool{
|
||||
"User-Agent": true,
|
||||
"X-Mobile": true,
|
||||
}
|
||||
}
|
||||
|
||||
type resp struct {
|
||||
code int
|
||||
_type string
|
||||
}
|
||||
|
||||
func Resp(r *fasthttp.Response) *resp {
|
||||
return &resp{
|
||||
code: r.StatusCode(),
|
||||
_type: bytes.NewBuffer(r.Header.ContentType()).String(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *resp) MarshalLogObject(enc zapcore.ObjectEncoder) error {
|
||||
enc.AddString("type", r._type)
|
||||
enc.AddInt("code", r.code)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type req struct {
|
||||
body string
|
||||
fullPath string
|
||||
user string
|
||||
ip string
|
||||
method string
|
||||
route string
|
||||
headers *headerbag
|
||||
}
|
||||
|
||||
func Req(c *fiber.Ctx) *req {
|
||||
reqq := c.Request()
|
||||
var body []byte
|
||||
buffer := new(bytes.Buffer)
|
||||
err := json.Compact(buffer, reqq.Body())
|
||||
if err != nil {
|
||||
body = reqq.Body()
|
||||
} else {
|
||||
body = buffer.Bytes()
|
||||
}
|
||||
|
||||
headers := &headerbag{
|
||||
vals: make(map[string]string),
|
||||
}
|
||||
allowedHeaders := getAllowedHeaders()
|
||||
reqq.Header.VisitAll(func(key, val []byte) {
|
||||
k := bytes.NewBuffer(key).String()
|
||||
if _, exist := allowedHeaders[k]; exist {
|
||||
headers.vals[strings.ToLower(k)] = bytes.NewBuffer(val).String()
|
||||
}
|
||||
})
|
||||
|
||||
var userEmail string
|
||||
if u := c.Locals("userEmail"); u != nil {
|
||||
userEmail = u.(string)
|
||||
}
|
||||
|
||||
return &req{
|
||||
body: bytes.NewBuffer(body).String(),
|
||||
fullPath: bytes.NewBuffer(reqq.RequestURI()).String(),
|
||||
headers: headers,
|
||||
ip: c.IP(),
|
||||
method: c.Method(),
|
||||
route: c.Route().Path,
|
||||
user: userEmail,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *req) MarshalLogObject(enc zapcore.ObjectEncoder) error {
|
||||
enc.AddString("fullPath", r.fullPath)
|
||||
enc.AddString("ip", r.ip)
|
||||
enc.AddString("method", r.method)
|
||||
enc.AddString("route", r.route)
|
||||
|
||||
if r.body != "" {
|
||||
enc.AddString("body", r.body)
|
||||
}
|
||||
|
||||
if r.user != "" {
|
||||
enc.AddString("user", r.user)
|
||||
}
|
||||
|
||||
err := enc.AddObject("headers", r.headers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type headerbag struct {
|
||||
vals map[string]string
|
||||
}
|
||||
|
||||
func (h *headerbag) MarshalLogObject(enc zapcore.ObjectEncoder) error {
|
||||
for k, v := range h.vals {
|
||||
enc.AddString(k, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user