go-kit 微服务 添加日志(并为每个请求添加UUID)
- 通过日志我们可以了解到我们关心的数据在软件内的执行情况,同时出问题时可以分析与定位系统故障
- 用户的每个请求都添加请求ID(我使用的UUID),我们可以更好的了解到每个请求的执行过程,更利于分析与定位问题
简介
- 在上篇文章中go-kit 微服务 基础使用(HTTP)我们实现了使用go-kit 构建一个简单的加法的http服务
- 这篇文章中我们将实现使用go-kit中间件机制为其增加日志功能
开始
下载依赖
- uuid库 go get github.com/satori/go.
- 日志库使用的是以前文章 Golang 高性能日志库 zap 封装工具类的日志工具
Server层修改
在Server层文件夹中创建middleware.go文件
- 定义服务中间件
type NewMiddlewareServer func(Service) Service
- 创建logMiddlewareServer结构体
type logMiddlewareServer struct {
logger *zap.Logger
next Service
}
- 创建NewLogMiddlewareServer把日志记录对象嵌入中间件(其实就是对Service添加了一层装饰)
func NewLogMiddlewareServer(log *zap.Logger) NewMiddlewareServer {
return func(service Service) Service {
return logMiddlewareServer{
logger: log,
next: service,
}
}
}
- 让logMiddlewareServer实现Service中的全部方法
func (l logMiddlewareServer) TestAdd(ctx context.Context, in Add) (out AddAck) {
defer func() {
l.logger.Debug(fmt.Sprint(ctx.Value(ContextReqUUid)), zap.Any("调用 v2_service logMiddlewareServer", "TestAdd"), zap.Any("req", in), zap.Any("res", out))
}()
out = l.next.TestAdd(ctx, in)
return out
}
修改Service中的代码
- baseServer结构体添加日志对象
type baseServer struct {
logger *zap.Logger
}
- 修改Service的初始化方法,加入日志中间件
func NewService(log *zap.Logger) Service {
var server Service
server = &baseServer{log}
server = NewLogMiddlewareServer(log)(server)
return server
}
Endpoint层修改
- 添加日志中间件
func LoggingMiddleware(logger *zap.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.Debug(fmt.Sprint(ctx.Value(v2_service.ContextReqUUid)), zap.Any("调用 v2_endpoint LoggingMiddleware", "处理完请求"), zap.Any("耗时毫秒", time.Since(begin).Milliseconds()))
}(time.Now())
return next(ctx, request)
}
}
}
- 在NewEndPointServer方法中为每个Endpoint添加日志中间件
func NewEndPointServer(svc v2_service.Service, log *zap.Logger) EndPointServer {
var addEndPoint endpoint.Endpoint
{
addEndPoint = MakeAddEndPoint(svc)
addEndPoint = LoggingMiddleware(log)(addEndPoint)
}
return EndPointServer{AddEndPoint: addEndPoint}
}
Transport层修改
- 为每个请求添加UUID
httptransport.ServerBefore(func(ctx context.Context, request *http.Request) context.Context {
UUID := uuid.NewV5(uuid.Must(uuid.NewV4()), "req_uuid").String()
log.Debug("给请求添加uuid", zap.Any("UUID", UUID))
ctx = context.WithValue(ctx, v2_service.ContextReqUUid, UUID)
return ctx
}
激动人心的时刻来了,修改main方法
utils.NewLoggerServer()
server := v2_service.NewService(utils.GetLogger())
endpoints := v2_endpoint.NewEndPointServer(server, utils.GetLogger())
httpHandler := v2_transport.NewHttpHandler(endpoints, utils.GetLogger())
utils.GetLogger().Info("server run 0.0.0.0:8888")
_ = http.ListenAndServe("0.0.0.0:8888", httpHandler)
访问 http://127.0.0.1:8888/sum?a=1&b=1
2020-01-02 10:21:43 INFO logtool/log.go:89 [NewLogger] success
2020-01-02 10:21:43 INFO v2/main.go:16 server run 0.0.0.0:8888
2020-01-02 10:22:00 DEBUG v2_transport/transport.go:27 给请求添加uuid {"UUID": "18f7e742-62ef-57ab-b96a-bfa87c654b50"}
2020-01-02 10:22:00 DEBUG v2_transport/transport.go:52 18f7e742-62ef-57ab-b96a-bfa87c654b50 {" 开始解析请求数据","b":1}}
2020-01-02 10:22:00 DEBUG v2_service/service.go:28 18f7e742-62ef-57ab-b96a-bfa87c654b50 {"调用 v2_service Seice": "TestAdd 处理请求"}
2020-01-02 10:22:00 DEBUG v2_service/service.go:30 18f7e742-62ef-57ab-b96a-bfa87c654b50 {"调用 v2_service Seice": "TestAdd 处理请求", "处理返回值": {"res":2}}
2020-01-02 10:22:00 DEBUG v2_service/middleware.go:29 18f7e742-62ef-57ab-b96a-bfa87c654b50 {"调用 v2_service loiddlewareServer": "TestAdd", "req": {"a":1,"b":1}, "res": {"res":2}}
2020-01-02 10:22:00 DEBUG v2_endpoint/middleware.go:16 18f7e742-62ef-57ab-b96a-bfa87c654b50 {"调用 v2_endpoint LgingMiddleware": "处理完请求", "耗时毫秒": 2}
2020-01-02 10:22:00 DEBUG v2_transport/transport.go:57 18f7e742-62ef-57ab-b96a-bfa87c654b50 {"请求结束封装返回值:2}}
- 有疑问请联系我
结语
git-kit的中间件采用的装饰者模式,所以新增的日志功能基本对各层逻辑基本没有侵入,方便中间件的插拔处理