这是我参与「第三届青训营 -后端场」笔记创作活动的第7篇笔记
Chapter 7
ZAP
quick start
suger logger
package main
import (
"go.uber.org/zap"
)
func main() {
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
// 第一个参数为msg, 之后为附加
sugar.Infow("from infow",
// Structured context as loosely typed key-value pairs.
"stutus", "ok",
)
// 直接写入msg
sugar.Infof("status %s", "ok")
}
// output:
// {"level":"info","ts":1639041275.566963,"caller":"suger/main.go:14","msg":"from infow","stutus":"ok"}
// {"level":"info","ts":1639041275.5670037,"caller":"suger/main.go:20","msg":"status ok"}
logger
package main
import (
"go.uber.org/zap"
)
func main() {
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
// 第一个参数为msg, 之后为附加
logger.Info("from info",
zap.String("status", "ok"),
zap.Int("code", 200),
)
}
// output:
// {"level":"info","ts":1639041198.5196414,"caller":"logger/main.go:12","msg":"from info","status":"ok","code":200}
To file
package main
import (
"go.uber.org/zap"
)
var logger *zap.Logger
func NewLogger() (*zap.Logger, error) {
config := zap.NewProductionConfig()
config.OutputPaths = append(config.OutputPaths, "./mylog.log")
return config.Build()
}
func main() {
logger, _ = NewLogger()
defer logger.Sync() // flushes buffer, if any
// 第一个参数为msg, 之后为附加
logger.Info("from info",
zap.String("status", "ok"),
zap.Int("code", 200),
)
}
// output:
// {"level":"info","ts":1639041666.5249786,"caller":"to_file/main.go:21","msg":"from info","status":"ok","code":200}
{"level":"info","ts":1639041666.5249786,"caller":"to_file/main.go:21","msg":"from info","status":"ok","code":200}
全局 logger zap.L() 与 全局 suger logger zap.S()
logger, _ = NewLogger()
defer logger.Sync() // flushes buffer, if any
zap.L().Info("global logger")
zap.S().Info("global suger logger")
直接调用全局 logger 并无输出, 它只是一个空壳.
func main() {
logger, _ = NewLogger()
defer logger.Sync() // flushes buffer, if any
zap.ReplaceGlobals(logger)
zap.L().Info("global logger")
zap.S().Info("global suger logger")
}
使用 zap.ReplaceGlobals(logger), 进行填充.
viper
Quick Start 读取配置到结构体, 热加载
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
type ServerConf struct {
APPName string `mapstructure:"appname"`
Version string `mapstructure:"version"`
}
var serverConf ServerConf
func main() {
// option 1
viper.SetConfigFile("./conf.yaml")
// option 2
//viper.SetConfigName("config")
//viper.SetConfigType("yaml")
//viper.AddConfigPath(".")
// 读取配置
if err := viper.ReadInConfig(); err != nil {
panic(fmt.Errorf("Fatal error config file: %w \n", err))
}
// 解析成结构体
if err := viper.Unmarshal(&serverConf); err != nil {
fmt.Println("Read Config failed\n", err)
}
// 热加载配置
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config was Changed: ", e.Name)
})
if err := viper.Unmarshal(&serverConf); err != nil {
fmt.Println("Read Config failed\n", err)
}
fmt.Println(serverConf.APPName)
fmt.Println(serverConf.Version)
}
// conf.yaml
appname: "app"
version: "0.0.1"
切换生产环境配置
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
type ServerConf struct {
APPName string `mapstructure:"appname"`
Version string `mapstructure:"version"`
}
var serverConf ServerConf
func Getenv(s string) int {
// 寻找系统中可用的环境变量
viper.AutomaticEnv()
return viper.GetInt(s)
}
func main() {
mode := Getenv("VIPER_MODE")
// 假设 0 为 线下配置
if mode == 0 {
viper.SetConfigFile("./conf.yaml")
}
// option 1
viper.SetConfigFile("./product.yaml")
// option 2
//viper.SetConfigName("config")
//viper.SetConfigType("yaml")
//viper.AddConfigPath(".")
// 读取配置
if err := viper.ReadInConfig(); err != nil {
panic(fmt.Errorf("Fatal error config file: %w \n", err))
}
// 解析成结构体
if err := viper.Unmarshal(&serverConf); err != nil {
fmt.Println("Read Config failed\n", err)
}
// 热加载配置
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config was Changed: ", e.Name)
})
if err := viper.Unmarshal(&serverConf); err != nil {
fmt.Println("Read Config failed\n", err)
}
fmt.Println(serverConf.APPName)
fmt.Println(serverConf.Version)
}