201 lines
6.3 KiB
Go
201 lines
6.3 KiB
Go
/**
|
||
* Tencent is pleased to support the open source community by making polaris-go available.
|
||
*
|
||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
||
*
|
||
* Licensed under the BSD 3-Clause License (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* https://opensource.org/licenses/BSD-3-Clause
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software distributed
|
||
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||
* specific language governing permissions and limitations under the License.
|
||
*/
|
||
|
||
package config
|
||
|
||
import (
|
||
"fmt"
|
||
"reflect"
|
||
"time"
|
||
|
||
"github.com/hashicorp/go-multierror"
|
||
"github.com/modern-go/reflect2"
|
||
"gopkg.in/yaml.v2"
|
||
|
||
"github.com/polarismesh/polaris-go/pkg/plugin/common"
|
||
)
|
||
|
||
// 插件配置类型
|
||
var pluginConfigTypes = make(map[common.Type]map[string]reflect.Type)
|
||
|
||
// RegisterPluginConfigType RegisterPlugin 注册插件到全局配置对象,并注册插件配置类型.
|
||
func RegisterPluginConfigType(typ common.Type, name string, cfg BaseConfig) {
|
||
if reflect2.IsNil(cfg) {
|
||
return
|
||
}
|
||
cfgTypes, exists := pluginConfigTypes[typ]
|
||
if !exists {
|
||
cfgTypes = make(map[string]reflect.Type)
|
||
pluginConfigTypes[typ] = cfgTypes
|
||
}
|
||
cfgTypes[name] = reflect.TypeOf(cfg).Elem()
|
||
}
|
||
|
||
// ErrorCountConfig 连续错误数熔断配置.
|
||
type ErrorCountConfig interface {
|
||
// GetContinuousErrorThreshold 连续错误数阈值
|
||
GetContinuousErrorThreshold() int
|
||
// SetContinuousErrorThreshold 设置连续错误数阈值
|
||
SetContinuousErrorThreshold(int)
|
||
// GetMetricStatTimeWindow 连续错误数统计时间窗口
|
||
GetMetricStatTimeWindow() time.Duration
|
||
// SetMetricStatTimeWindow 设置连续错误数统计时间窗口
|
||
SetMetricStatTimeWindow(time.Duration)
|
||
// GetMetricNumBuckets 连续错误数统计滑桶数量
|
||
GetMetricNumBuckets() int
|
||
// SetMetricNumBuckets 设置连续错误数统计滑桶数量
|
||
SetMetricNumBuckets(int)
|
||
// GetBucketInterval 获取单个滑桶的时间间隔
|
||
GetBucketInterval() time.Duration
|
||
}
|
||
|
||
// ErrorRateConfig 错误率熔断配置.
|
||
type ErrorRateConfig interface {
|
||
// GetRequestVolumeThreshold 触发错误率熔断的请求量阈值
|
||
GetRequestVolumeThreshold() int
|
||
// SetRequestVolumeThreshold 设置触发错误率熔断的请求量阈值
|
||
SetRequestVolumeThreshold(int)
|
||
// GetErrorRatePercent 触发熔断的错误率阈值,取值范围(0, 100]
|
||
GetErrorRatePercent() int
|
||
// SetErrorRatePercent 设置错误率阈值
|
||
SetErrorRatePercent(int)
|
||
// GetMetricStatTimeWindow 错误率统计时间窗口
|
||
GetMetricStatTimeWindow() time.Duration
|
||
// SetMetricStatTimeWindow 设置错误率统计时间窗口
|
||
SetMetricStatTimeWindow(time.Duration)
|
||
// GetMetricNumBuckets 统计窗口细分的桶数量
|
||
GetMetricNumBuckets() int
|
||
// SetMetricNumBuckets 设置统计窗口细分的桶数量
|
||
SetMetricNumBuckets(int)
|
||
// GetBucketInterval 获取单个滑桶的时间间隔
|
||
GetBucketInterval() time.Duration
|
||
}
|
||
|
||
// PluginConfigs 插件配置实现类.
|
||
type PluginConfigs map[string]interface{}
|
||
|
||
// getPluginConfigTypes 获取插件配置类型,返回插件名到类型的映射.
|
||
func getPluginConfigTypes(typ common.Type) map[string]reflect.Type {
|
||
plugs, exists := pluginConfigTypes[typ]
|
||
if !exists {
|
||
return nil
|
||
}
|
||
return plugs
|
||
}
|
||
|
||
// getPluginConfigType 获取插件配置类型,具体插件类型.
|
||
func getPluginConfigType(typ common.Type, name string) (reflect.Type, bool) {
|
||
plugs, exists := pluginConfigTypes[typ]
|
||
if !exists {
|
||
return nil, false
|
||
}
|
||
if plugCfg, ok := plugs[name]; ok {
|
||
return plugCfg, ok
|
||
}
|
||
return nil, false
|
||
}
|
||
|
||
// Init 初始化配置对象.
|
||
func (p PluginConfigs) Init(typ common.Type) {
|
||
cfgTypes := getPluginConfigTypes(typ)
|
||
for name, cfgType := range cfgTypes {
|
||
value := reflect.New(cfgType).Interface()
|
||
p[name] = value
|
||
}
|
||
}
|
||
|
||
// convertFromTextValues 对于从yaml/json加载的结构,做一个转换.
|
||
func convertFromTextValues(cfgType reflect.Type, cfgValue interface{}) BaseConfig {
|
||
// 如果在配置文件中没有相关内容,直接创建一个配置对象返回即可
|
||
if reflect2.IsNil(cfgValue) {
|
||
return reflect.New(cfgType).Interface().(BaseConfig)
|
||
}
|
||
var jsonValues map[interface{}]interface{}
|
||
var ok bool
|
||
if jsonValues, ok = cfgValue.(map[interface{}]interface{}); !ok {
|
||
return cfgValue.(BaseConfig)
|
||
}
|
||
configValue := reflect.New(cfgType).Interface()
|
||
buf, _ := yaml.Marshal(jsonValues)
|
||
_ = yaml.Unmarshal(buf, configValue)
|
||
return configValue.(BaseConfig)
|
||
}
|
||
|
||
// SetDefault 设置默认值.
|
||
func (p PluginConfigs) SetDefault(typ common.Type) {
|
||
for plugName := range p {
|
||
// 如果不是注册进来的配置项,从PluginConfigs里面删除掉
|
||
if _, exists := getPluginConfigType(typ, plugName); !exists {
|
||
delete(p, plugName)
|
||
continue
|
||
}
|
||
}
|
||
configTypes := getPluginConfigTypes(typ)
|
||
if configTypes == nil {
|
||
return
|
||
}
|
||
for pluginName, configType := range configTypes {
|
||
cfg := convertFromTextValues(configType, p[pluginName])
|
||
cfg.SetDefault()
|
||
p[pluginName] = cfg
|
||
}
|
||
}
|
||
|
||
// Verify 校验插件配置.
|
||
func (p PluginConfigs) Verify() error {
|
||
for name, cfgValue := range p {
|
||
cfg, ok := cfgValue.(BaseConfig)
|
||
if !ok {
|
||
continue
|
||
}
|
||
// 检验插件配置
|
||
if err := cfg.Verify(); err != nil {
|
||
return fmt.Errorf("fail to verify plugin %s config, err is %v", name, err)
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// SetPluginConfig 设置单独一个插件的值.
|
||
func (p PluginConfigs) SetPluginConfig(plugType common.Type, plugName string, value BaseConfig) error {
|
||
configType, exists := getPluginConfigType(plugType, plugName)
|
||
if !exists {
|
||
return fmt.Errorf("config not registered for plugin(type %s, name %s)", plugType, plugName)
|
||
}
|
||
valueType := reflect.TypeOf(value).Elem()
|
||
if valueType != configType {
|
||
return fmt.Errorf("type %s not match config type %s for plugin(type %s, name %s)",
|
||
valueType, configType, plugType, plugName)
|
||
}
|
||
value.SetDefault()
|
||
err := value.Verify()
|
||
if err != nil {
|
||
return multierror.Prefix(err, "Fail to verify config value of "+plugType.String()+":"+plugName+": ")
|
||
}
|
||
p[plugName] = value
|
||
return nil
|
||
}
|
||
|
||
// GetPluginConfig 根据插件名获取配置.
|
||
func (p PluginConfigs) GetPluginConfig(pluginName string) BaseConfig {
|
||
cfg, ok := p[pluginName]
|
||
if !ok {
|
||
return nil
|
||
}
|
||
return cfg.(BaseConfig)
|
||
}
|