zoukankan      html  css  js  c++  java
  • 26.使用中间件的方式包装日志输出

    使用中间件的方式包装日志输出

    package Services
    
    import (
        "context"
        "fmt"
        "github.com/go-kit/kit/endpoint"
        "github.com/go-kit/kit/log"
        "golang.org/x/time/rate"
        "gomicro/utils"
        "strconv"
    )
    
    type UserRequest struct { //封装User请求结构体
        Uid    int `json:"uid"`
        Method string
    }
    
    type UserResponse struct {
        Result string `json:"result"`
    }
    
    //日志中间件,每一个service都应该有自己的日志中间件
    func UserServiceLogMiddleware(logger log.Logger) endpoint.Middleware { //Middleware type Middleware func(Endpoint) Endpoint
        return func(next endpoint.Endpoint) endpoint.Endpoint { //Endpoint type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
            return func(ctx context.Context, request interface{}) (response interface{}, err error) {
                r := request.(UserRequest) //通过类型断言获取请求结构体
                logger.Log("method", r.Method, "event", "get user", "userid", r.Uid)
                return next(ctx, request)
            }
        }
    }
    
    //加入限流功能中间件
    func RateLimit(limit *rate.Limiter) endpoint.Middleware { //Middleware type Middleware func(Endpoint) Endpoint
        return func(next endpoint.Endpoint) endpoint.Endpoint { //Endpoint type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
            return func(ctx context.Context, request interface{}) (response interface{}, err error) {
                if !limit.Allow() {
                    return nil, utils.NewMyError(429, "toot many request")
                }
                return next(ctx, request)
            }
        }
    }
    
    func GenUserEnPoint(userService IUserService) endpoint.Endpoint {
        return func(ctx context.Context, request interface{}) (response interface{}, err error) {
            r := request.(UserRequest) //通过类型断言获取请求结构体
            result := "nothings"
            if r.Method == "GET" {
                result = userService.GetName(r.Uid) + strconv.Itoa(utils.ServicePort)
    
            } else if r.Method == "DELETE" {
                err := userService.DelUser(r.Uid)
                if err != nil {
                    result = err.Error()
                } else {
                    result = fmt.Sprintf("userid为%d的用户已删除", r.Uid)
                }
            }
            return UserResponse{Result: result}, nil
        }
    }
    

    调用日志中间件

    package main
    
    import (
        "flag"
        "fmt"
        kitlog "github.com/go-kit/kit/log"
        httptransport "github.com/go-kit/kit/transport/http"
        mymux "github.com/gorilla/mux"
        "golang.org/x/time/rate"
        "gomicro/Services"
        "gomicro/utils"
        "log"
        "net/http"
        "os"
        "os/signal"
        "strconv"
        "syscall"
    )
    
    func main() {
        go func() {}()
        go (func() {})()
        name := flag.String("name", "", "服务名称")
        port := flag.Int("port", 0, "服务端口")
        flag.Parse()
        if *name == "" {
            log.Fatal("请指定服务名")
        }
        if *port == 0 {
            log.Fatal("请指定端口")
        }
        var logger kitlog.Logger
        {
            logger = kitlog.NewLogfmtLogger(os.Stdout)
            logger = kitlog.WithPrefix(logger, "mykit", "1.0")
            logger = kitlog.WithPrefix(logger, "time", kitlog.DefaultTimestampUTC) //加上前缀时间
            logger = kitlog.WithPrefix(logger, "caller", kitlog.DefaultCaller)     //加上前缀,日志输出时的文件和第几行代码
    
        }
        utils.SetServiceNameAndPort(*name, *port) //设置服务名和端口
    
        user := Services.UserService{}
        limit := rate.NewLimiter(1, 5)
        endp := Services.RateLimit(limit)(Services.UserServiceLogMiddleware(logger)(Services.GenUserEnPoint(user)))
        /*我们分析一下上面这段代码Services.RateLimit(limit)返回一个Middware,type Middleware func(Endpoint) Endpoint
        也就是说这段代码的返回值必须是Endpoint类型
        type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
        才可以传入Middware (Services.UserServiceLogMiddleware(logger)(Services.GenUserEnPoint(user)))
    
        再拆分Services.UserServiceLogMiddleware(logger)也返回一个Middware,同理Services.GenUserEnPoint(user)必然是返回一个EndPoint,这里GenUserEnPoint(user)返回值是
        func(ctx context.Context, request interface{}) (response interface{}, err error)所以是EndPoint类型
        那么(Services.UserServiceLogMiddleware(logger)是middleware,Services.GenUserEnPoint(user))值作为参数是Endpoint,返回值依然是一个Endpoint,这个返回值作为参数传递给了Services.RateLimit(limit),Services.RateLimit(limit)也是一个Middware,所以这样写是成立的
        */
    
        options := []httptransport.ServerOption{
            httptransport.ServerErrorEncoder(Services.MyErrorEncoder),
        }
    
        serverHandler := httptransport.NewServer(endp, Services.DecodeUserRequest, Services.EncodeUserResponse, options...) //使用go kit创建server传入我们之前定义的两个解析函数
    
        r := mymux.NewRouter()
        //r.Handle(`/user/{uid:d+}`, serverHandler) //这种写法支持多种请求方式
        r.Methods("GET", "DELETE").Path(`/user/{uid:d+}`).Handler(serverHandler) //这种写法仅支持Get,限定只能Get请求
        r.Methods("GET").Path("/health").HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
            writer.Header().Set("Content-type", "application/json")
            writer.Write([]byte(`{"status":"ok"}`))
        })
        errChan := make(chan error)
        go func() {
            utils.RegService()                                                 //调用注册服务程序
            err := http.ListenAndServe(":"+strconv.Itoa(utils.ServicePort), r) //启动http服务
            if err != nil {
                log.Println(err)
                errChan <- err
            }
        }()
        go func() {
            sigChan := make(chan os.Signal)
            signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
            errChan <- fmt.Errorf("%s", <-sigChan)
        }()
        getErr := <-errChan
        utils.UnRegService()
        log.Println(getErr)
    }
    




  • 相关阅读:
    linux软件安装方式
    docker 安装 jenkins touch: cannot touch ‘/var/jenkins_home/copy_reference_file.log’: Permission denied Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
    [ERR] Node goodsleep.vip:6379 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
    Linux 常用命令 服务器间scp 用户 export 创建文件、软连接
    redis 安装 集群 主从 哨兵 docker
    WPF密码框中禁止复制、粘贴
    Application 统计在线人数
    【转义字符】HTML 字符实体&lt; &gt: &amp;等
    SQL语句统计每天的数据
    正则表达式计算代码数
  • 原文地址:https://www.cnblogs.com/hualou/p/12089267.html
Copyright © 2011-2022 走看看