diff --git a/engine/statmetrics.go b/engine/statmetrics.go index ee91570a2..7904d55a0 100644 --- a/engine/statmetrics.go +++ b/engine/statmetrics.go @@ -33,24 +33,34 @@ import ( "github.com/ericlagergren/decimal" ) +type metricConstructor func(uint64, string, []string) StatMetric +type metricConstructorErr func(uint64, string, []string) (StatMetric, error) + +// withErrReturn wraps a constructor to return an error (always nil). +func withErrReturn(fn metricConstructor) metricConstructorErr { + return func(minItems uint64, extraParams string, filterIDs []string) (StatMetric, error) { + return fn(minItems, extraParams, filterIDs), nil + } +} + // NewStatMetric instantiates the StatMetric // cfg serves as general purpose container to pass config options to metric func NewStatMetric(metricID string, minItems uint64, filterIDs []string) (sm StatMetric, err error) { - metrics := map[string]func(uint64, string, []string) StatMetric{ - utils.MetaASR: NewASR, - utils.MetaACD: NewACD, - utils.MetaTCD: NewTCD, - utils.MetaACC: NewACC, - utils.MetaTCC: NewTCC, - utils.MetaPDD: NewPDD, - utils.MetaDDC: NewDDC, - utils.MetaSum: NewStatSum, - utils.MetaAverage: NewStatAverage, - utils.MetaDistinct: NewStatDistinct, - utils.MetaHighest: NewStatHighest, - utils.MetaLowest: NewStatLowest, - utils.MetaREPSC: NewStatREPSC, - utils.MetaREPFC: NewStatREPFC, + metrics := map[string]metricConstructorErr{ + utils.MetaASR: withErrReturn(NewASR), + utils.MetaACD: withErrReturn(NewACD), + utils.MetaTCD: withErrReturn(NewTCD), + utils.MetaACC: withErrReturn(NewACC), + utils.MetaTCC: withErrReturn(NewTCC), + utils.MetaPDD: withErrReturn(NewPDD), + utils.MetaDDC: withErrReturn(NewDDC), + utils.MetaSum: NewStatSum, // Already returns (StatMetric, error) + utils.MetaAverage: withErrReturn(NewStatAverage), + utils.MetaDistinct: withErrReturn(NewStatDistinct), + utils.MetaHighest: withErrReturn(NewStatHighest), + utils.MetaLowest: withErrReturn(NewStatLowest), + utils.MetaREPSC: withErrReturn(NewStatREPSC), + utils.MetaREPFC: withErrReturn(NewStatREPFC), } // split the metricID // in case of *sum we have *sum#~*req.FieldName @@ -62,7 +72,7 @@ func NewStatMetric(metricID string, minItems uint64, filterIDs []string) (sm Sta if len(metricSplit[1:]) > 0 { extraParams = metricSplit[1] } - return metrics[metricSplit[0]](minItems, extraParams, filterIDs), nil + return metrics[metricSplit[0]](minItems, extraParams, filterIDs) } // StatMetric is the interface which a metric should implement @@ -771,12 +781,15 @@ func (m *Metric) Equal(v *Metric) bool { return true } -func NewStatSum(minItems uint64, fieldName string, filterIDs []string) StatMetric { - flds, _ := utils.NewRSRParsers(fieldName, utils.InfieldSep) +func NewStatSum(minItems uint64, fieldName string, filterIDs []string) (StatMetric, error) { + flds, err := utils.NewRSRParsers(fieldName, utils.InfieldSep) + if err != nil { + return nil, err + } return &StatSum{ Metric: NewMetric(minItems, filterIDs), Fields: flds, - } + }, nil } type StatSum struct { diff --git a/engine/statmetrics_test.go b/engine/statmetrics_test.go index f157615ef..81e5c2ad9 100644 --- a/engine/statmetrics_test.go +++ b/engine/statmetrics_test.go @@ -2101,7 +2101,10 @@ func TestDDCGetCompressFactor(t *testing.T) { } func TestStatSumGetFloat64Value(t *testing.T) { - statSum := NewStatSum(2, "~*opts.*cost", nil) + statSum, err := NewStatSum(2, "~*opts.*cost", nil) + if err != nil { + t.Fatal(err) + } ev := &utils.CGREvent{ID: "EVENT_1", APIOpts: map[string]any{ utils.MetaDestination: "1002", @@ -2165,7 +2168,10 @@ func TestStatSumGetFloat64Value(t *testing.T) { } func TestStatSumGetStringValue(t *testing.T) { - statSum := NewStatSum(2, "~*opts.*cost", nil) + statSum, err := NewStatSum(2, "~*opts.*cost", nil) + if err != nil { + t.Fatal(err) + } ev := &utils.CGREvent{ID: "EVENT_1", APIOpts: map[string]any{ utils.MetaDestination: "1002", @@ -2210,7 +2216,10 @@ func TestStatSumGetStringValue(t *testing.T) { } func TestStatSumGetStringValue2(t *testing.T) { - statSum := NewStatSum(2, "~*opts.*cost", nil) + statSum, err := NewStatSum(2, "~*opts.*cost", nil) + if err != nil { + t.Fatal(err) + } ev1 := &utils.CGREvent{ID: "EVENT_1", APIOpts: map[string]any{utils.MetaCost: 12.3}} if err := statSum.AddEvent(ev1.ID, utils.MapStorage{utils.MetaOpts: ev1.APIOpts}); err != nil { @@ -2383,7 +2392,10 @@ func TestStatSumGetCompressFactor(t *testing.T) { "EVENT_1": 1, "EVENT_2": 1, } - sum := NewStatSum(2, "~*opts.*cost", nil) + sum, err := NewStatSum(2, "~*opts.*cost", nil) + if err != nil { + t.Fatal(err) + } ev := &utils.CGREvent{ID: "EVENT_1", APIOpts: map[string]any{utils.MetaCost: 18.2}} ev2 := &utils.CGREvent{ID: "EVENT_2", @@ -3034,7 +3046,10 @@ func TestDCCMarshal(t *testing.T) { } func TestStatSumMarshal(t *testing.T) { - statSum := NewStatSum(2, "~*opts.*cost", nil) + statSum, err := NewStatSum(2, "~*opts.*cost", nil) + if err != nil { + t.Fatal(err) + } ev := &utils.CGREvent{ID: "EVENT_1", APIOpts: map[string]any{ utils.MetaDestination: "1002", diff --git a/engine/stats_test.go b/engine/stats_test.go index b2e115491..dd9dfa3f8 100644 --- a/engine/stats_test.go +++ b/engine/stats_test.go @@ -32,6 +32,14 @@ import ( "github.com/cgrates/cgrates/utils" ) +func mustNewStatSum(minItems uint64, fieldName string, filterIDs []string) StatMetric { + sum, err := NewStatSum(minItems, fieldName, filterIDs) + if err != nil { + panic(err) + } + return sum +} + var ( testStatsPrfs = []*StatQueueProfile{ { @@ -104,7 +112,7 @@ var ( ID: "StatQueueProfile1", sqPrfl: testStatsPrfs[0], SQMetrics: map[string]StatMetric{ - utils.MetaSum: NewStatSum(1, "~*req.Usage", nil), + utils.MetaSum: mustNewStatSum(1, "~*req.Usage", nil), }, }, { @@ -112,7 +120,7 @@ var ( ID: "StatQueueProfile2", sqPrfl: testStatsPrfs[1], SQMetrics: map[string]StatMetric{ - utils.MetaSum: NewStatSum(1, "~*req.Usage", nil), + utils.MetaSum: mustNewStatSum(1, "~*req.Usage", nil), }, }, { @@ -120,7 +128,7 @@ var ( ID: "StatQueueProfilePrefix", sqPrfl: testStatsPrfs[2], SQMetrics: map[string]StatMetric{ - utils.MetaSum: NewStatSum(1, "~*req.Usage", nil), + utils.MetaSum: mustNewStatSum(1, "~*req.Usage", nil), }, }, }