01:基础功能封装
Kratos入库文件 cmd/
- 接收命令参数
- 创建日志对象 Logger
- 读取配置文件
接下来我们将这部分通用代码进行封装;代码将放到项目目录的pkg/bootstrap 下
启动参数处理
为了是程序更加灵活通常会将一些参数在程序启动时传入;比如运行环境,配置文件路径等;接下来我们已接收conf(本地 文件配置); env (运行环境如 dev 开发 ;pro 生产);consul (consul 远程配置 地址) 三个参数为例进行封装;代码:
package bootstrap
import "flag"
type CommandFlags struct {
Conf string // 文件配置
Env string // 运行环境 dev 开发 ;pro 生产
Consul string // consul 远程配置 地址
}
func NewCommandFlags() *CommandFlags {
return &CommandFlags{
Conf: "",
Env: "",
Consul: "",
}
}
func (f *CommandFlags) Init() {
flag.StringVar(&f.Conf, "conf", "../../configs", "config path, eg: -conf bootstrap.yaml")
flag.StringVar(&f.Env, "env", "dev", "runtime environment, eg: -env dev")
flag.StringVar(&f.Consul, "consul", "", "config server host, eg: -consul http://127.0.0.1:8500")
}
接收命令行参数用到了flag包;需要注意的是在入库文件调用封装方法后需要执行 flag.Parse() 如:
func init() {
Flags = bootstrap.NewCommandFlags()
Flags.Init()
flag.Parse()
}
日志处理
Kratos提供了统一的日志处理组件和日志接入抽象;通过实现Logger 对象可以很方便的实现自定义日志处理逻辑;log.DefaultLogger 可以将日志信息打印到控制台;如果将日志输出到文件中可以考虑通过zap包做封装;代码可以参考kratos-example; 代码如下:
import (
"fmt"
"os"
"time"
"github.com/go-kratos/kratos/v2/log"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var _ log.Logger = (*ZapLogger)(nil)
// ZapLogger is a logger impl.
type ZapLogger struct {
log *zap.Logger
Sync func() error
}
// NewZapLogger return a zap logger.
func NewZapLogger(encoder zapcore.EncoderConfig, prefix string, level zap.AtomicLevel, opts ...zap.Option) *ZapLogger {
rotateLogger, err := rotatelogs.New("./log/"+prefix+"_%Y%m%d.log", rotatelogs.WithMaxAge(time.Hour*24*30))
if err != nil {
log.Fatalf("logger.Setup err: %v", err)
}
core := zapcore.NewCore(
zapcore.NewConsoleEncoder(encoder),
zapcore.NewMultiWriteSyncer(
zapcore.AddSync(os.Stdout), //输出到控制台上
zapcore.AddSync(rotateLogger), //输出到文本中
), level)
zapLogger := zap.New(core, opts...)
return &ZapLogger{log: zapLogger, Sync: zapLogger.Sync}
}
func (l *ZapLogger) Log(level log.Level, keyvals ...interface{}) error {
if len(keyvals) == 0 || len(keyvals)%2 != 0 {
l.log.Warn(fmt.Sprint("Keyvalues must appear in pairs: ", keyvals))
return nil
}
var data []zap.Field
for i := 0; i < len(keyvals); i += 2 {
data = append(data, zap.Any(fmt.Sprint(keyvals[i]), fmt.Sprint(keyvals[i+1])))
}
switch level {
case log.LevelDebug:
l.log.Debug("", data...)
case log.LevelInfo:
l.log.Info("", data...)
case log.LevelWarn:
l.log.Warn("", data...)
case log.LevelError:
l.log.Error("", data...)
}
return nil
}
其中通过 rotatelogs 进行日志文件的滚动
读取配置文件
Kratos的config组件可以很方便的从各种配置源加载配置;比如从文件中读取:
path := "configs/config.yaml"
c := config.New(
config.WithSource(
file.NewSource(path),
)
)
因为之前接收参数是分别接收了本地配置文件和consul远程配置参数;对应的将这两种读取配置的方式做一下封装。
// getConfigKey 获取合法的配置名
func getConfigKey(configKey string, useBackslash bool) string {
if useBackslash {
return strings.Replace(configKey, `.`, `/`, -1)
} else {
return configKey
}
}
// NewConsulConfigSource 创建一个远程配置源 - Consul
func NewConsulConfigSource(configHost, configKey string) config.Source {
consulClient, err := api.NewClient(&api.Config{
Address: configHost,
})
if err != nil {
panic(err)
}
consulSource, err := consulKratos.New(consulClient,
consulKratos.WithPath(getConfigKey(configKey, true)),
)
if err != nil {
panic(err)
}
return consulSource
}
// NewFileConfigSource 创建一个本地文件配置源
func NewFileConfigSource(filePath string) config.Source {
return file.NewSource(filePath)
}