github.com/zly-app/zapp@v1.3.3/config/config.go (about) 1 /* 2 ------------------------------------------------- 3 Author : zlyuancn 4 date: 2021/1/20 5 Description : 6 ------------------------------------------------- 7 */ 8 9 package config 10 11 import ( 12 "bytes" 13 "encoding/json" 14 "flag" 15 "fmt" 16 "os" 17 "strings" 18 19 "github.com/spf13/viper" 20 "go.uber.org/zap" 21 22 "github.com/zly-app/zapp/consts" 23 "github.com/zly-app/zapp/core" 24 "github.com/zly-app/zapp/logger" 25 "github.com/zly-app/zapp/pkg/utils" 26 "github.com/zly-app/zapp/pkg/zlog" 27 ) 28 29 var Conf core.IConfig 30 31 type configCli struct { 32 vi *viper.Viper 33 c *core.Config 34 flags map[string]struct{} 35 labels map[string]string 36 } 37 38 func newConfig(appName string) *core.Config { 39 conf := &core.Config{ 40 Frame: core.FrameConfig{ 41 Debug: true, 42 FreeMemoryInterval: consts.DefaultFreeMemoryInterval, 43 Labels: make(map[string]string), 44 Log: zlog.DefaultConfig, 45 PrintConfig: true, 46 }, 47 } 48 conf.Frame.Log.Name = appName 49 return conf 50 } 51 52 // 解析配置 53 // 54 // 配置来源优先级 命令行 > WithViper > WithConfig > WithFiles(Apollo分片优先级最高) > WithApollo > 默认配置文件 55 // 注意: 多个配置文件如果存在同配置分片会智能合并, 同分片中完全相同的配置节点以最后的文件为准, 从apollo拉取的配置会覆盖相同的文件配置节点 56 func NewConfig(appName string, opts ...Option) core.IConfig { 57 opt := newOptions() 58 for _, o := range opts { 59 o(opt) 60 } 61 62 confText := flag.String("c", "", "配置文件,多个文件用逗号隔开,同名配置分片会完全覆盖之前的分片") 63 testFlag := flag.Bool("t", false, "测试配置文件") 64 flag.Parse() 65 66 var rawVi *viper.Viper 67 var err error 68 if *confText != "" { // 命令行 69 files := strings.Split(*confText, ",") 70 rawVi, err = makeViperFromFile(files, false) 71 if err != nil { 72 logger.Log.Fatal("从命令指定文件加载失败", zap.Error(err)) 73 } 74 } else if opt.vi != nil { // WithViper 75 rawVi = opt.vi 76 } else if opt.conf != nil { // WithConfig 77 rawVi, err = makeViperFromStruct(opt.conf) 78 if err != nil { 79 logger.Log.Fatal("从配置结构构建viper失败", zap.Any("config", opt.conf), zap.Error(err)) 80 } 81 } else if len(opt.files) > 0 { // WithFiles 82 rawVi, err = makeViperFromFile(opt.files, false) 83 if err != nil { 84 logger.Log.Fatal("从用户指定文件构建viper失败", zap.Error(err)) 85 } 86 } else if opt.apolloConfig != nil { // WithApollo 87 rawVi = viper.New() 88 rawVi.Set(consts.ApolloConfigKey, opt.apolloConfig) 89 } else if rawVi = loadDefaultFiles(); rawVi != nil { 90 } 91 92 vi := viper.New() 93 if rawVi != nil { 94 if err := vi.MergeConfigMap(rawVi.AllSettings()); err != nil { 95 logger.Log.Fatal("合并配置文件失败", zap.Error(err)) 96 } 97 } 98 99 // 如果发现包含配置 100 if vi.IsSet(consts.IncludeConfigFileKey) { 101 vi = loadIncludeConfigFile(vi) 102 } 103 104 // 如果从viper中发现了apollo配置 105 if vi.IsSet(consts.ApolloConfigKey) { 106 apolloConf, err := makeApolloConfigFromViper(vi) 107 if err != nil { 108 logger.Log.Fatal("解析apollo配置失败", zap.Error(err)) 109 } 110 rawVi, err = makeViperFromApollo(apolloConf) 111 if err != nil { 112 logger.Log.Fatal("从apollo构建viper失败", zap.Error(err)) 113 } 114 if err = vi.MergeConfigMap(rawVi.AllSettings()); err != nil { 115 logger.Log.Fatal("合并apollo配置失败", zap.Error(err)) 116 } 117 } 118 119 c := &configCli{ 120 vi: vi, 121 c: newConfig(appName), 122 } 123 // 解析配置 124 if err = vi.Unmarshal(c.c); err != nil { 125 logger.Log.Fatal("配置解析失败", zap.Error(err)) 126 } 127 128 c.checkDefaultConfig(c.c) 129 130 if *testFlag { 131 logger.Log.Info("配置文件测试成功") 132 os.Exit(0) 133 } 134 135 c.makeFlags() 136 c.makeLabels() 137 138 Conf = c 139 return c 140 } 141 142 func (c *configCli) makeFlags() { 143 c.flags = make(map[string]struct{}, len(c.c.Frame.Flags)) 144 for _, flag := range c.c.Frame.Flags { 145 c.flags[strings.ToLower(flag)] = struct{}{} 146 } 147 148 flags := make([]string, 0, len(c.flags)) 149 for flag := range c.flags { 150 flags = append(flags, flag) 151 } 152 c.c.Frame.Flags = flags 153 } 154 155 func (c *configCli) makeLabels() { 156 c.labels = make(map[string]string, len(c.c.Frame.Labels)) 157 for k, v := range c.c.Frame.Labels { 158 c.labels[strings.ToLower(k)] = v 159 } 160 c.c.Frame.Labels = c.labels 161 } 162 163 // 加载默认配置文件, 默认配置文件不存在返回nil 164 func loadDefaultFiles() *viper.Viper { 165 files := strings.Split(consts.DefaultConfigFiles, ",") 166 vi := viper.New() 167 for _, file := range files { 168 _, err := os.Stat(file) 169 if err != nil { 170 if os.IsNotExist(err) { 171 continue 172 } 173 logger.Log.Fatal("读取配置文件信息失败", zap.String("file", file), zap.Error(err)) 174 } 175 176 vi.SetConfigFile(file) 177 if err = vi.MergeInConfig(); err != nil { 178 logger.Log.Fatal("合并配置文件失败", zap.String("file", file), zap.Error(err)) 179 } 180 logger.Log.Info("使用默认配置文件", zap.String("file", file)) 181 return vi 182 } 183 return nil 184 } 185 186 // 合并文件到viper 187 func mergeFile(vi *viper.Viper, file string, ignoreNotExist bool) error { 188 _, err := os.Stat(file) 189 if err != nil { 190 if os.IsNotExist(err) { 191 if ignoreNotExist { 192 logger.Log.Warn("配置文件不存在", zap.String("file", file)) 193 return nil 194 } 195 return fmt.Errorf("配置文件不存在") 196 } 197 return fmt.Errorf("读取配置文件信息失败: %s", err) 198 } 199 200 vi.SetConfigFile(file) 201 if err = vi.MergeInConfig(); err != nil { 202 return err 203 } 204 return nil 205 } 206 207 // 从文件构建viper 208 func makeViperFromFile(files []string, ignoreNotExist bool) (*viper.Viper, error) { 209 vi := viper.New() 210 for _, file := range files { 211 if err := mergeFile(vi, file, ignoreNotExist); err != nil { 212 return nil, fmt.Errorf("合并配置文件'%s'失败: %s", file, err.Error()) 213 } 214 } 215 return vi, nil 216 } 217 218 // 从结构体构建viper 219 func makeViperFromStruct(a interface{}) (*viper.Viper, error) { 220 bs, err := json.Marshal(a) 221 if err != nil { 222 return nil, fmt.Errorf("编码失败: %s", err) 223 } 224 225 vi := viper.New() 226 vi.SetConfigType("json") 227 err = vi.ReadConfig(bytes.NewReader(bs)) 228 if err != nil { 229 return nil, fmt.Errorf("数据解析失败: %s", err) 230 } 231 return vi, nil 232 } 233 234 // 加载包含配置文件 235 func loadIncludeConfigFile(vi *viper.Viper) *viper.Viper { 236 var temp struct { 237 Files string 238 } 239 err := vi.UnmarshalKey(consts.IncludeConfigFileKey, &temp) 240 if err != nil { 241 logger.Log.Fatal("include配置错误", zap.Error(err)) 242 } 243 244 files := strings.Split(temp.Files, ",") 245 for _, file := range files { 246 if err := mergeFile(vi, file, false); err != nil { 247 logger.Log.Fatal("合并包含文件失败", zap.String("file", file), zap.Error(err)) 248 } 249 } 250 return vi 251 } 252 253 func (c *configCli) checkDefaultConfig(conf *core.Config) { 254 if conf.Frame.Name != "" { 255 conf.Frame.Log.Name = conf.Frame.Name 256 } 257 conf.Frame.WaitServiceRunTime = utils.Ternary.Or(conf.Frame.WaitServiceRunTime, consts.DefaultWaitServiceRunTime).(int) 258 conf.Frame.ServiceUnstableObserveTime = utils.Ternary.Or(conf.Frame.ServiceUnstableObserveTime, consts.DefaultServiceUnstableObserveTime).(int) 259 } 260 261 func (c *configCli) Config() *core.Config { 262 return c.c 263 } 264 265 func (c *configCli) GetViper() *viper.Viper { 266 return c.vi 267 } 268 269 func (c *configCli) Parse(key string, outPtr interface{}, ignoreNotSet ...bool) error { 270 if !c.vi.IsSet(key) { 271 if len(ignoreNotSet) > 0 && ignoreNotSet[0] { 272 return nil 273 } 274 return fmt.Errorf("key<%s>不存在", key) 275 } 276 if err := c.vi.UnmarshalKey(key, outPtr); err != nil { 277 return fmt.Errorf("无法解析key<%s>配置: %s", key, err) 278 } 279 return nil 280 } 281 282 func (c *configCli) ParseComponentConfig(componentType core.ComponentType, componentName string, outPtr interface{}, ignoreNotSet ...bool) error { 283 componentName = utils.Ternary.Or(componentName, consts.DefaultComponentName).(string) 284 key := "components." + string(componentType) + "." + componentName 285 if !c.vi.IsSet(key) { 286 if len(ignoreNotSet) > 0 && ignoreNotSet[0] { 287 return nil 288 } 289 return fmt.Errorf("组件配置<%s.%s>不存在", componentType, componentName) 290 } 291 if err := c.vi.UnmarshalKey(key, outPtr); err != nil { 292 return fmt.Errorf("无法解析<%s.%s>组件配置: %s", componentType, componentName, err) 293 } 294 return nil 295 } 296 297 func (c *configCli) ParsePluginConfig(pluginType core.PluginType, outPtr interface{}, ignoreNotSet ...bool) error { 298 key := "plugins." + string(pluginType) 299 if !c.vi.IsSet(key) { 300 if len(ignoreNotSet) > 0 && ignoreNotSet[0] { 301 return nil 302 } 303 return fmt.Errorf("插件配置<%s>不存在", pluginType) 304 } 305 if err := c.vi.UnmarshalKey(key, outPtr); err != nil { 306 return fmt.Errorf("无法解析<%s>插件配置: %s", pluginType, err) 307 } 308 return nil 309 } 310 311 func (c *configCli) ParseServiceConfig(serviceType core.ServiceType, outPtr interface{}, ignoreNotSet ...bool) error { 312 key := "services." + string(serviceType) 313 if !c.vi.IsSet(key) { 314 if len(ignoreNotSet) > 0 && ignoreNotSet[0] { 315 return nil 316 } 317 return fmt.Errorf("服务配置<%s>不存在", serviceType) 318 } 319 if err := c.vi.UnmarshalKey(key, outPtr); err != nil { 320 return fmt.Errorf("无法解析<%s>服务配置: %s", serviceType, err) 321 } 322 return nil 323 } 324 325 func (c *configCli) GetLabel(name string) string { 326 return c.labels[strings.ToLower(name)] 327 } 328 329 func (c *configCli) GetLabels() map[string]string { 330 return c.labels 331 } 332 333 func (c *configCli) HasFlag(flag string) bool { 334 _, ok := c.flags[strings.ToLower(flag)] 335 return ok 336 } 337 338 func (c *configCli) GetFlags() []string { 339 return c.c.Frame.Flags 340 }