go中中间件(日志、请求、错误等)

  1. panic错误导致系统异常、返回给前端一堆乱码,可以通过中间件处理panic错误,代码:

// GinRecovery recover掉项目可能出现的panic
func GinRecovery(stack bool) gin.HandlerFunc {
    return func(c *gin.Context) {
        defer func() {
            if err := recover(); err != nil {
                // Check for a broken connection, as it is not really a
                // condition that warrants a panic stack trace.
                var brokenPipe bool
                if ne, ok := err.(*net.OpError); ok {
                    if se, ok := ne.Err.(*os.SyscallError); ok {
                        if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
                            brokenPipe = true
                        }
                    }
                }

                httpRequest, _ := httputil.DumpRequest(c.Request, false)
                if brokenPipe {
                    global.Logger.Errorf(string(httpRequest), err, c.Request.URL.Path)
                    // If the connection is dead, we can't write a status to it.
                    _ = c.Error(err.(error)) // nolint: err
                    c.Abort()
                    return
                }

                if stack {
                    //打印日志
                   log.Errorf("[Recovery from panic]", err, "[ERROR]:"+string(debug.Stack()[:]))
                } else {
                    log.Errorf("[Recovery from panic]", err, "[ERROR]:"+string(httpRequest))
                }
               //前台返回
                response := app.NewResponse(c)
                response.ToErrorResponse(errcode.ServerError.WithDetails(fmt.Sprintf("%v", err)))
                c.Abort()
            }
        }()
        c.Next()
    }
}
  1. 每个请求调用时长中间件,代码如下:

type AccessLogWriter struct {
    gin.ResponseWriter
    body *bytes.Buffer
}

func (w AccessLogWriter) Write(p []byte) (int, error) {
    if n, err := w.body.Write(p); err != nil {
        return n, err
    }
    return w.ResponseWriter.Write(p)
}
func AccessLog() gin.HandlerFunc {
    return func(context *gin.Context) {
        bodyWriter := &AccessLogWriter{body: bytes.NewBufferString(""), ResponseWriter: context.Writer}
        context.Writer = bodyWriter
        beginTime := time.Now().Unix()
        context.Next()
        endTime := time.Now().Unix()
            log.Info("AccessLog", fmt.Sprintf("method:%v,url:%v,status_code:%d,begin_time:%d,end_time:%d,info:%v",
                context.Request.Method,
                context.Request.URL,
                bodyWriter.Status(),
                beginTime,
                endTime,
                bodyWriter.body.String()))
    }
}

3、链路追踪中间件,代码如下:

func setupTracer() error {
    jaegerTracer, _, err := tracer.NewJaegerTracer("blog_service", "127.0.0.1:6831")
    if err != nil {
        return err
    }
    global.Tracer = jaegerTracer
    return nil
}

package middleware

import (
    "context"
    "github.com/gin-gonic/gin"
    "github.com/opentracing/opentracing-go"
    "github.com/uber/jaeger-client-go"
    "xxxxx/blog-service/global"
)

func Tracing() func(c *gin.Context) {
    return func(c *gin.Context) {
        var ctx context.Context
        span := opentracing.SpanFromContext(c.Request.Context())
        if span != nil {
            span, ctx = opentracing.StartSpanFromContextWithTracer(c.Request.Context(), global.Tracer, c.Request.URL.Path)
            defer span.Finish()
            c.Request = c.Request.WithContext(ctx)
            c.Next()
        }
        var traceID string
        var spanID string
        var spanContext = span.Context()
        switch spanContext.(type) {
        case jaeger.SpanContext:
            traceID = spanContext.(jaeger.SpanContext).TraceID().String()
            spanID = spanContext.(jaeger.SpanContext).SpanID().String()
            c.Set("X-Trace-ID", traceID)
            c.Set("X-Span-ID", spanID)
            c.Request = c.Request.WithContext(ctx)
            c.Next()
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值