本质上讲,go-kit中间件采用了装饰者模式,传入Endpoint对象,封装部分业务逻辑,然后返回Endpoint对象。
我们通过给service层添加日志功能来说明一下
新建middleware.go文件,加入如下代码:
import (
"github.com/go-kit/kit/log"
)
const ContextReqUUid = "req_uuid"
type ServiceMiddleware func(Service) Service
接下来,新建类型logMiddlewareServer,该类型中嵌入了Service,还包含一个logger属性,代码如下所示:
type logMiddlewareServer struct {
logger log.Logger
next Service
}
再创建一个方法LogMiddlewareServer把日志记录对象嵌入中间件。该方法接受日志对象,返回ServiceMiddleware ,而ServiceMiddleware 可以传入Service对象,这样就可以对Service增加一层装饰。代码如下:
func LogMiddlewareServer(log log.Logger) ServiceMiddleware {
return func(next Service) Service {
return logMiddlewareServer{
logger: log,
next: next,
}
}
}
接下来就可以让新的类型logMiddlewareServer 实现Service的接口方法了。实现方法时可以在其中使用日志对象记录调用方法、调用时间、传入参数、输出结果、调用耗时等信息。下面以Add方法为例进行实现,其他方法与之类似:
func (l logMiddlewareServer) Add(a, b int) int {
l.logger.Log("function", "Add", "a", a, "b", b, )
return l.next.Add(a, b)
}
打开main.go,调用LogMiddlewareServer创建日志中间件实现对svc的包装,代码如下所示
package main
import (
"context"
"fmt"
"github.com/go-kit/kit/log"
"go_study/gokit/gokit_log/endpoints"
"go_study/gokit/gokit_log/services"
"go_study/gokit/gokit_log/transports"
"net/http"
"os"
"os/signal"
"syscall"
)
func main() {
ctx := context.Background()
errChan := make(chan error)
var logger log.Logger
{
logger = log.NewLogfmtLogger(os.Stderr)
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
logger = log.With(logger, "caller", log.DefaultCaller)
}
var svc services.Service
svc = services.ArithmeticService{}
// add logging middleware
svc = services.LogMiddlewareServer(logger)(svc)
endpoint := endpoints.MakeArithmeticEndpoint(svc)
handler := transports.MakeHttpHandler(ctx, endpoint, logger)
go func() {
fmt.Println("Http Server start at port:9000")
errChan <- http.ListenAndServe(":9000", handler)
}()
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
errChan <- fmt.Errorf("%s", <-c)
}()
fmt.Println(<-errChan)
}
运行效果就不展示了,现在只是对service添加了log日志,接下来对endpoint层也添加下日志功能,相比service层,endpoint层添加日志功能就很容易了,直接上代码
新建middleware.go文件,加入如下代码:
package endpoints
import (
"context"
"github.com/go-kit/kit/endpoint"
"github.com/go-kit/kit/log"
"time"
)
func LoggingMiddleware(logger log.Logger) endpoint.Middleware {
return func(next endpoint.Endpoint) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
defer func(begin time.Time) {
logger.Log("endpoint", request.(ArithmeticRequest).RequestType)
}(time.Now())
return next(ctx, request)
}
}
}
打开main.go,调用LoggingMiddleware创建日志中间件实现对endpoint的包装,代码如下所示
endpoint := endpoints.MakeArithmeticEndpoint(svc)
// add logging middleware
endpoint=endpoints.LoggingMiddleware(logger)(endpoint)
endpoint层就添加好了,效果就不贴了
参考: