Go-kit
Go kit教程04——中间件和日志
本文主要介绍了Go kit 中的中间件,并以日志中间件为例演示了如何设计和实现中间件。
 上一篇中,我们对go kit搭建的项目进行了目录结构拆分
中间件
在 go kit 中,它对中间件的定义是一个接收Endpoint并返回Endpoint的函数,具体定义如下。
type Middleware func(Endpoint) Endpoint
 
在中间件接收Endpoint参数和返回Endpoint之间,你可以做任何事。
例如,下面的示例演示了如何实现一个基础的日志中间件。
import (
	"context"
	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/log"
)
func loggingMiddleware(logger log.Logger) endpoint.Middleware {
	return func(next endpoint.Endpoint) endpoint.Endpoint {
		return func(ctx context.Context, request interface{}) (interface{}, error) {
			logger.Log("msg", "calling endpoint")
			defer logger.Log("msg", "called endpoint")
			return next(ctx, request)
		}
	}
}
 
transport层日志
这里想要记录transport层的日志信息,将先前的NewHTTPServer按如下方式进行改造即可。
func NewHTTPServer(svc AddService, logger log.Logger) http.Handler {
	// sum
	sum := makeSumEndpoint(svc)
	// 使用loggingMiddleware为sum端点加上日志
	sum = loggingMiddleware(log.With(logger, "method", "sum"))(sum)
	sumHandler := httptransport.NewServer(
		sum,
		decodeSumRequest,
		encodeResponse,
	)
	// concat
	concat := makeConcatEndpoint(svc)
	// 使用loggingMiddleware为concat端点加上日志
	concat = loggingMiddleware(log.With(logger, "method", "concat"))(concat)
	concatHandler := httptransport.NewServer(
		concat,
		decodeConcatRequest,
		encodeResponse,
	)
	r := gin.Default()
	r.POST("/sum", gin.WrapH(sumHandler))
	r.POST("/concat", gin.WrapH(concatHandler))
	return r
}
 

应用层日志
第一种 引用全局的logger

第二种 结构体注入 (缺点:后期更改日志工具不方便)

 
官方方法
如果要在应用程序层面添加日志,例如需要记录下详细的请求参数,那么就需要为我们的服务来定义中间件。
由于我们的 AddService 服务定义为接口类型,所以我们只需要定义一个新类型(把原先的实现和一个额外的logger包装起来)并实现这个接口即可。
先定义类型。
type logMiddleware struct {
	logger log.Logger
	next   AddService
}
 
再实现接口。
func (mw logMiddleware) Sum(ctx context.Context, a, b int) (res int, err error) {
	defer func(begin time.Time) {
		mw.logger.Log(
			"method", "sum",
			"a", a,
			"b", b,
			"output", res,
			"err", err,
			"took", time.Since(begin),
		)
	}(time.Now())
	res, err = mw.next.Sum(ctx, a, b)
	return
}
func (mw logMiddleware) Concat(ctx context.Context, a, b string) (res string, err error) {
	defer func(begin time.Time) {
		mw.logger.Log(
			"method", "sum",
			"a", a,
			"b", b,
			"output", res,
			"err", err,
			"took", time.Since(begin),
		)
	}(time.Now())
	res, err = mw.next.Concat(ctx, a, b)
	return
}
// NewLogMiddleware 创建一个带日志的add service
func NewLogMiddleware(logger log.Logger, svc AddService) AddService {
	return &logMiddleware{
		logger: logger,
		next:   svc,
	}
}
 

集成zap日志库
上述示例默认使用的是github.com/go-kit/log,你也可以使用其他的日志库,例如下面示例中使用社区常用的zap日志库。
 
ratelimit限流中间件
import "golang.org/x/time/rate"
var (
	ErrRateLimit = errors.New("request rate limit")
)
// rateMiddleware 限流中间件
func rateMiddleware(limit *rate.Limiter) endpoint.Middleware {
	return func(next endpoint.Endpoint) endpoint.Endpoint {
		return func(ctx context.Context, request interface{}) (interface{}, error) {
			if !limit.Allow() {
				return nil, ErrRateLimit
			}
			return next(ctx, request)
		}
	}
}
 
使用限流中间件。
import "golang.org/x/time/rate"
sum = rateMiddleware(rate.NewLimiter(1, 1))(sum)
 
Go-Zero
连接mysql

mysql -uroot -p -hlocalhost



使用 goctl model mysql … 自动生成model 可选择在最后加上 -c 来生成带缓存的代码


加不加缓存对于逻辑层是无感知的,但是需要添加上配置以连接缓存
日志 logx
在开发阶段需要查看一些信息的,可以使用debug级别或者Info级别日志
 对于私密的信息不允许落盘和网络传输的使用debug级别日志
 而对于需要探究哪出错的日志,使用Error级别
使用docker启动mysql、redis、etcd、grpcui
mysql
docker run --name mysql -e MYSQL_ROOT_PASSWORD=123 -d mysql:latest
redis
docker pull redis
docker run --name reids -e redis_password=123 -d redis:latest
etcd
docker run -it --name Etcd bitnami/etcd
grpcui
go install github.com/fullstorydev/grpcui/cmd/grpcui@latest
















![Modelsim仿真问题解疑二:ERROR: [USF-ModelSim-70]](https://img-blog.csdnimg.cn/img_convert/b31ab1d00592df0a0871369166ec3bf1.png)


