stats: add error return for StatSum constructor

refactor NewStatMetric to also account for metric constructors that
return error
This commit is contained in:
ionutboangiu
2025-11-12 18:11:36 +02:00
committed by Dan Christian Bogos
parent ce720a259d
commit 0c2b9a403a
3 changed files with 63 additions and 27 deletions

View File

@@ -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 {

View File

@@ -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",

View File

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