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)
|
|||
|
}
|