HoraeMeta is written in Golang so the basic code style we adhere to is the CodeReviewComments.
Besides the CodeReviewComments, there are also some custom rules for the project:
- Error Handling
- Logging
- Global error code:
- Any error defined in the repo should be assigned an error code,
- An error code can be used by multiple different errors,
- The error codes are defined in the single global package coderr.
- Construct: define leaf errors on package level (often in a separate
error.go
file) by package coderr. - Wrap: wrap errors by
errors.WithMessage
orerrors.WithMessagef
. - Check: test the error identity by calling
coderr.Is
. - Log: only log the error on the top level package.
- Respond: respond the
CodeError
(defined in package coderr) unwrapped byerrors.Cause
to client on service level.
errors.go
in the package server
:
var ErrStartEtcd = coderr.NewCodeError(coderr.Internal, "start embed etcd")
var ErrStartEtcdTimeout = coderr.NewCodeError(coderr.Internal, "start etcd server timeout")
server.go
in the package server
:
func (srv *Server) startEtcd() error {
etcdSrv, err := embed.StartEtcd(srv.etcdCfg)
if err != nil {
return ErrStartEtcd.WithCause(err)
}
newCtx, cancel := context.WithTimeout(srv.ctx, srv.cfg.EtcdStartTimeout())
defer cancel()
select {
case <-etcdSrv.Server.ReadyNotify():
case <-newCtx.Done():
return ErrStartEtcdTimeout.WithCausef("timeout is:%v", srv.cfg.EtcdStartTimeout())
}
return nil
}
main.go
in the package main
:
func main() {
err := srv.startEtcd()
if err != nil {
return
}
if coderr.Is(err, coderr.Internal) {
log.Error("internal error")
}
cerr, ok := err.(coderr.CodeError)
if ok {
log.Error("found a CodeError")
} else {
log.Error("not a CodeError)
}
return
}
- Structured log by zap.
- Use the package
github.com/horaemeta/pkg/log
which is based on zap. - Create local logger with common fields if necessary.
Normal usage:
import "github.com/horaemeta/pkg/log"
func main() {
if err := srv.Run(); err != nil {
log.Error("fail to run server", zap.Error(err))
return
}
}
Local logger:
import "github.com/horaemeta/pkg/log"
type lease struct {
ID int64
logger *zap.Logger
}
func NewLease(ID int64) *lease {
logger := log.With(zap.Int64("lease-id", ID))
return &lease {
ID,
logger,
}
}
func (l *lease) Close() {
l.logger.Info("lease is closed")
l.ID = 0
}