ext/datasource/hotspot_rule_converter.go (92 lines of code) (raw):

// Copyright 1999-2020 Alibaba Group Holding Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // 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 datasource import ( "fmt" "strconv" "github.com/alibaba/sentinel-golang/core/hotspot" "github.com/alibaba/sentinel-golang/logging" "github.com/pkg/errors" ) type HotspotRule struct { // ID is the unique id ID string `json:"id,omitempty"` // Resource is the resource name Resource string `json:"resource"` // MetricType indicates the metric type for checking logic. // For Concurrency metric, hotspot module will check the each hot parameter's concurrency, // if concurrency exceeds the Threshold, reject the traffic directly. // For QPS metric, hotspot module will check the each hot parameter's QPS, // the ControlBehavior decides the behavior of traffic shaping controller MetricType hotspot.MetricType `json:"metricType"` // ControlBehavior indicates the traffic shaping behaviour. // ControlBehavior only takes effect when MetricType is QPS ControlBehavior hotspot.ControlBehavior `json:"controlBehavior"` // ParamIndex is the index in context arguments slice. // if ParamIndex is great than or equals to zero, ParamIndex means the <ParamIndex>-th parameter // if ParamIndex is the negative, ParamIndex means the reversed <ParamIndex>-th parameter ParamIndex int `json:"paramIndex"` // Threshold is the threshold to trigger rejection Threshold int64 `json:"threshold"` // MaxQueueingTimeMs only takes effect when ControlBehavior is Throttling and MetricType is QPS MaxQueueingTimeMs int64 `json:"maxQueueingTimeMs"` // BurstCount is the silent count // BurstCount only takes effect when ControlBehavior is Reject and MetricType is QPS BurstCount int64 `json:"burstCount"` // DurationInSec is the time interval in statistic // DurationInSec only takes effect when MetricType is QPS DurationInSec int64 `json:"durationInSec"` // ParamsMaxCapacity is the max capacity of cache statistic ParamsMaxCapacity int64 `json:"paramsMaxCapacity"` SpecificItems []SpecificValue `json:"specificItems"` } // ParamKind represents the Param kind. type ParamKind int const ( KindInt ParamKind = iota KindString KindBool KindFloat64 KindSum ) func (t ParamKind) String() string { switch t { case KindInt: return "KindInt" case KindString: return "KindString" case KindBool: return "KindBool" case KindFloat64: return "KindFloat64" default: return "Undefined" } } // SpecificValue indicates the specific param, contain the supported param kind and concrete value. type SpecificValue struct { ValKind ParamKind `json:"valKind"` ValStr string `json:"valStr"` Threshold int64 `json:"threshold"` } func (s *SpecificValue) String() string { return fmt.Sprintf("SpecificValue: [ValKind: %+v, ValStr: %s]", s.ValKind, s.ValStr) } // parseSpecificItems parses the SpecificValue as real value. func parseSpecificItems(source []SpecificValue) map[interface{}]int64 { ret := make(map[interface{}]int64, len(source)) if len(source) == 0 { return ret } for _, item := range source { switch item.ValKind { case KindInt: realVal, err := strconv.Atoi(item.ValStr) if err != nil { logging.Error(errors.Wrap(err, "parseSpecificItems error"), "Failed to parse value for int specific item", "itemValKind", item.ValKind, "itemValStr", item.ValStr) continue } ret[realVal] = item.Threshold case KindString: ret[item.ValStr] = item.Threshold case KindBool: realVal, err := strconv.ParseBool(item.ValStr) if err != nil { logging.Error(errors.Wrap(err, "parseSpecificItems error"), "Failed to parse value for bool specific item", "itemValStr", item.ValStr) continue } ret[realVal] = item.Threshold case KindFloat64: realVal, err := strconv.ParseFloat(item.ValStr, 64) if err != nil { logging.Error(errors.Wrap(err, "parseSpecificItems error"), "Failed to parse value for float specific item", "itemValStr", item.ValStr) continue } realVal, err = strconv.ParseFloat(fmt.Sprintf("%.5f", realVal), 64) if err != nil { logging.Error(errors.Wrap(err, "parseSpecificItems error"), "Failed to parse value for float specific item", "itemValStr", item.ValStr) continue } ret[realVal] = item.Threshold default: logging.Error(errors.New("Unsupported kind for specific item"), "", item.ValKind) } } return ret }