paas-api 代码规范

目录结构

  1. .
  2. ├── Dockerfile // 构建使用的Dockerfile文件
  3. ├── LICENSE
  4. ├── Makefile // 本地开发、调试方便使用
  5. ├── README.md // README
  6. ├── app.dev.cfg // 开发配置文件
  7. ├── app.prod.cfg // 生产配置文件
  8. ├── app.test.cfg // 测试配置文件
  9. ├── cmd // 入口
  10. ├── client // 客户端测试
  11. └── client.go
  12. ├── main.go // 入口main
  13. └── service
  14. ├── service.go // 启动前的基础配置,各个模块的实例化、数据库等外部资源的连接初始化都在这
  15. ├── service_gen.go // 数据库命令行操作
  16. ├── service_setting.go // 系统设置命令行操作
  17. ├── service_sore.go // 初始化验证码仓库
  18. ├── service_start.go // 启动服务, http、grpc初始化都会在这
  19. └── service_tracer.go // 初始化tracer
  20. ├── docker-compose.yaml
  21. ├── docs // 文档目录
  22. ├── go.mod // go依赖
  23. ├── go.sum
  24. ├── src // 源
  25. ├── api // 所有连接外部的api统一出入口
  26. ├── alarm // 统一告警中心api
  27. ├── logging.go // 日志
  28. ├── service.go // 实现逻辑
  29. ├── service_test.go // 单元测试
  30. └── tracing.go // 链路
  31. ├── api.go // 初始化各个外部api服务
  32. ├── encode // 处理response的逻辑包
  33. ├── response.go // response处理逻辑
  34. └── responsestatus.go // 错误码定义
  35. ├── helpers // helpers
  36. └── hashids // 生成唯一码
  37. └── hashids.go
  38. ├── jwt // jwt
  39. └── jwt.go
  40. ├── kubernetes // 连接k8s客户端实现逻辑
  41. ├── client.go
  42. ├── logging.go
  43. └── tracing.go
  44. ├── logging // 全局日志配置
  45. └── logging.go // 输出的方式,及未被定义的错误会在这进行处理
  46. ├── middleware // 全局、上层中间件
  47. ├── access.go // 授权验证中间件
  48. ├── asd.go // 登陆验证中间件
  49. ├── audit.go // 审计中间件
  50. ├── cluster.go // 集群验证中间件
  51. ├── limitter.go // 限流中间件
  52. ├── namespace.go // 项目空间处理中间件
  53. └── tracing.go // 链路追踪中间件
  54. ├── pkg // 业务模块包
  55. ├── access // 授权管理模块
  56. ├── endpoint.go // 端点连接request,middleware,service,response
  57. ├── http.go // 处理http请求
  58. ├── logging.go // 处理grpc请求
  59. ├── service.go // 具体业务逻辑代码
  60. └── tracing.go // 链路追踪
  61. ├── auth // 登陆授权模块
  62. ├── endpoint.go // 端点连接request,middleware,service,response
  63. ├── http.go // 处理http请求
  64. ├── instrumenting.go // 模块指标监控 给prometheus的监控指标
  65. ├── logging.go // 日志
  66. ├── middleware.go // 本模块独立中间件
  67. ├── service.go // 具体业务逻辑代码
  68. └── tracing.go // 链路追踪
  69. ├── openapi // 开放API模块,对外开放的接口模块,只对开放API使用,其他模块不允许调用业务功能多的时候可能会独立出出去
  70. ├── nginx // nginx操作业务模块
  71. ├── endpoint.go // 端点连接request,middleware,service,response
  72. ├── http.go // 处理http请求
  73. ├── grpc.go // 处理grpc请求
  74. ├── pb // grpc 的pb文件
  75. ├── logging.go // 日志
  76. ├── middleware.go // 本模块独立中间件
  77. ├── service.go // 具体业务逻辑代码
  78. └── tracing.go // 链路追踪
  79. └── user // 用户相关操作业务模块
  80. ├── endpoint.go // 端点连接request,middleware,service,response
  81. ├── http.go // 处理http请求
  82. ├── logging.go // 日志
  83. ├── service.go // 具体业务逻辑代码
  84. ├── service_test.go // 单元测试
  85. └── tracing.go // 链路追踪
  86. ├── redis // redis客户端
  87. ├── redis.go
  88. └── redis_middleware.go
  89. ├── repository // 数据仓库处理逻辑
  90. ├── access // access 相关表数据库操作逻辑实现包
  91. ├── cache.go // 缓存
  92. ├── logging.go // 日志
  93. ├── service.go // 实现逻辑
  94. └── tracing.go // 链路
  95. ├── repository.go // 连接各个数据库、数据表的统一出入口,实现各各表操作逻辑初始化
  96. └── types // 数据库表结构定义
  97. ├── auth_access.go
  98. ├── auth_resource.go
  99. ├── auth_service.go
  100. └── util // util包
  101. ├── aes.go
  102. ├── tests // 单元测试
  103. ├── README.md
  104. ├── grpc_test.go
  105. └── service_client_test.go
  106. └── web // 前端文件

代码规范

格式化代码

Golang 代码使用 goimports 和 gofmt 进行代码格式化

命名规范

文件名命名规范

用小写,尽量见名思义,看见文件名就可以知道这个文件下的大概内容,对于源代码里的文件,文件名要很好的代表了一个模块实现的功能。

src/ 目录下创建的是可公用的组件,src/pkg/下是各个功能模块,模块之间可以相互调用。

包名

保持 package 的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。命名尽量不使用分隔符。

模块包规范

新增加的模块必须在src/pkg目录下,每个模块只干该模块该干的事,基础文件有service.go、logging.go、endpoint.go、http.go、tracing.go、service_test.go

logging.go 参考:

  1. import (
  2. "context"
  3. "github.com/go-kit/kit/log"
  4. "github.com/go-kit/kit/log/level"
  5. "time"
  6. )
  7. type logging struct {
  8. logger log.Logger
  9. next Service
  10. traceId string
  11. }
  12. func (l *logging) Push(ctx context.Context, title, content, metrics, project, service string, level Level, silencePeriod int) (err error) {
  13. defer func(begin time.Time) {
  14. _ = l.logger.Log(
  15. l.traceId, ctx.Value(l.traceId),
  16. "method", "Push",
  17. "title", title,
  18. "content", content,
  19. "metrics", metrics,
  20. "project", project,
  21. "service", service,
  22. "level", level,
  23. "silencePeriod", silencePeriod,
  24. "took", time.Since(begin),
  25. "err", err,
  26. )
  27. }(time.Now())
  28. return l.next.Push(ctx, title, content, metrics, project, service, level, silencePeriod)
  29. }
  30. func NewLogging(logger log.Logger, traceId string) Middleware {
  31. logger = log.With(logger, "api.alarm", "logging")
  32. return func(next Service) Service {
  33. return &logging{
  34. logger: level.Info(logger),
  35. next: next,
  36. traceId: traceId,
  37. }
  38. }
  39. }

tracing.go 参考:

  1. import (
  2. "context"
  3. "github.com/opentracing/opentracing-go"
  4. "github.com/opentracing/opentracing-go/ext"
  5. )
  6. type tracing struct {
  7. next Service
  8. tracer opentracing.Tracer
  9. }
  10. func (s *tracing) Push(ctx context.Context, title, content, metrics, project, service string, level Level, silencePeriod int) (err error) {
  11. span, ctx := opentracing.StartSpanFromContextWithTracer(ctx, s.tracer, "Push", opentracing.Tag{
  12. Key: string(ext.Component),
  13. Value: "Api.Alarm",
  14. })
  15. defer func() {
  16. span.LogKV(
  17. "title", title,
  18. "content", content,
  19. "metrics", metrics,
  20. "project", project,
  21. "service", service,
  22. "level", level,
  23. "silencePeriod", silencePeriod,
  24. "err", err)
  25. span.SetTag(string(ext.Error), err != nil)
  26. span.Finish()
  27. }()
  28. return s.next.Push(ctx, title, content, metrics, project, service, level, silencePeriod)
  29. }
  30. func NewTracing(otTracer opentracing.Tracer) Middleware {
  31. return func(next Service) Service {
  32. return &tracing{
  33. next: next,
  34. tracer: otTracer,
  35. }
  36. }
  37. }

service.go 里的每个方法必须带有一个logging方法,日志输打印入参入出参和错误信息。

接口规范

定义一个接口:

  1. type Service interface {
  2. // Delete 删除Pod, 根据pod名称删除pod
  3. // clusterId: 中间件取得
  4. // ns: 空间标识
  5. // podName: 需要删除的pod名称
  6. Delete(ctx context.Context, clusterId int64, ns, podName string) (err error)
  7. }

接口的实现:

  1. type Middleware func(Service) Service
  2. type service struct {
  3. traceId string
  4. logger log.Logger
  5. k8sClient kubernetes.K8sClient
  6. config *config.Config
  7. }
  8. func New(logger log.Logger, traceId string, k8sClient kubernetes.K8sClient,
  9. config *config.Config) Service {
  10. return &service{traceId, logger, k8sClient, config}
  11. }
  12. func (s *service) Delete(ctx context.Context, clusterId int64, ns, podName string) (err error) {
  13. // ...
  14. return
  15. }

变量

  • 局部变量:驼峰式,小写字母开头
  • 全局变量:变量名采用驼峰标准

如:

  1. var (
  2. lineReadLimit int64 = 5000
  3. byteReadLimit int64 = 5000000
  4. )

常量

常量全部以驼峰式大写字母开头的方式命名:

  1. type ASDContext string
  2. const (
  3. ContextKeyClusterName ASDContext = "ctx-cluster-name" // 集群名称
  4. ContextKeyClusterId ASDContext = "ctx-cluster-id" // 集群ID
  5. ContextKeyNamespaceName ASDContext = "ctx-namespace-name" // 空间标识
  6. ContextKeyNamespaceId ASDContext = "ctx-namespace-id" // 集群id
  7. )

错误处理命名

错误处理的原则就是不能丢弃任何有返回 err 的调用,不要采用_丢弃,必须全部处理。接收到错误,要么返回 err,并用 log记录下来。 error 的信息不要采用大写字母,尽量保持你的错误简短,但是要足够表达你的错误的意思。所有的错误全部定义在src/encode/responsestatus.go上

除了在man.go可以使用panic外,其于地方一率不得使用panic。

错误变量名以Err开头,接包名最后接具体的错误 Err{pkg}NotFound: xxx 未找到

命名参考:

  1. type ResStatus string
  2. var ResponseMessage = map[ResStatus]int{
  3. ErrAccessSave: 2501,
  4. ErrAccessNotfound: 2502,
  5. ErrAccessResourceNotfound: 2503,
  6. ErrAccessResourceExpireTime: 2504,
  7. }
  8. const (
  9. ErrAccessSave ResStatus = "保存失败"
  10. ErrAccessNotfound ResStatus = "授权不存在"
  11. ErrAccessResourceNotfound ResStatus = "授权资源不存在"
  12. ErrAccessResourceExpireTime ResStatus = "授权已过期"
  13. )

未来被定义的错误信息会统一返回“系统错误”,并发出一条告警信息到统一告警中心。

使用方式

直接返回错误:

  1. return encode.ErrAccessNotfound.Error()

拼接上层错误:

  1. var err = errors.New("parent error.")
  2. return encode.ErrAccessNotfound.Wrap(err)

返回字符串错误:

  1. return encode.ErrAccessNotfound.String()