diff --git a/engine/libstats.go b/engine/libstats.go index 08d6b3354..96c22cbad 100644 --- a/engine/libstats.go +++ b/engine/libstats.go @@ -19,9 +19,12 @@ along with this program. If not, see package engine import ( + "bytes" + "encoding/gob" "encoding/json" "fmt" "sort" + "strings" "sync" "time" @@ -343,18 +346,20 @@ func (sis StatQueues) Sort() { sort.Slice(sis, func(i, j int) bool { return sis[i].sqPrfl.Weight > sis[j].sqPrfl.Weight }) } +type encStatQueue struct { + Tenant string + ID string + SQItems []SQItem + SQMetrics map[string]StatMetric +} + func (sq *StatQueue) MarshalJSON() (rply []byte, err error) { if sq == nil { return []byte("null"), nil } guardian.Guardian.Guard(context.Background(), func(*context.Context) (_ interface{}, _ error) { sq.RLock() - rply, err = json.Marshal(struct { - Tenant string - ID string - SQItems []SQItem - SQMetrics map[string]StatMetric - }{ + rply, err = json.Marshal(&encStatQueue{ Tenant: sq.Tenant, ID: sq.ID, SQItems: sq.SQItems, @@ -366,4 +371,69 @@ func (sq *StatQueue) MarshalJSON() (rply []byte, err error) { return } -// func (sq *StatQueue) GobEncode() ([]byte, error) +// UnmarshalJSON here only to fully support json for StatQueue +func (sq *StatQueue) UnmarshalJSON(data []byte) (err error) { + var tmp struct { + Tenant string + ID string + SQItems []SQItem + SQMetrics map[string]json.RawMessage + } + if err = json.Unmarshal(data, &tmp); err != nil { + return + } + sq.Tenant = tmp.Tenant + sq.ID = tmp.ID + sq.SQItems = tmp.SQItems + sq.SQMetrics = make(map[string]StatMetric) + for metricID, val := range tmp.SQMetrics { + metricSplit := strings.Split(metricID, utils.HashtagSep) + var metric StatMetric + switch metricSplit[0] { + case utils.MetaASR: + metric = new(StatASR) + case utils.MetaACD: + metric = new(StatACD) + case utils.MetaTCD: + metric = new(StatTCD) + case utils.MetaACC: + metric = new(StatACC) + case utils.MetaTCC: + metric = new(StatTCC) + case utils.MetaPDD: + metric = new(StatPDD) + case utils.MetaDDC: + metric = new(StatDDC) + case utils.MetaSum: + metric = new(StatSum) + case utils.MetaAverage: + metric = new(StatAverage) + case utils.MetaDistinct: + metric = new(StatDistinct) + default: + return fmt.Errorf("unsupported metric type <%s>", metricSplit[0]) + } + if err = json.Unmarshal([]byte(val), metric); err != nil { + fmt.Println(1) + return + } + sq.SQMetrics[metricID] = metric + } + return +} + +func (sq *StatQueue) GobEncode() (rply []byte, err error) { + buf := bytes.NewBuffer(rply) + guardian.Guardian.Guard(context.Background(), func(*context.Context) (_ interface{}, _ error) { + sq.RLock() + err = gob.NewEncoder(buf).Encode(&encStatQueue{ + Tenant: sq.Tenant, + ID: sq.ID, + SQItems: sq.SQItems, + SQMetrics: sq.SQMetrics, + }) + sq.RUnlock() + return + }, config.CgrConfig().GeneralCfg().LockingTimeout, utils.StatQueuePrefix+sq.TenantID()) + return buf.Bytes(), nil +} diff --git a/engine/libstats_test.go b/engine/libstats_test.go index 697dc6196..4d60fbc7e 100644 --- a/engine/libstats_test.go +++ b/engine/libstats_test.go @@ -18,6 +18,7 @@ along with this program. If not, see package engine import ( + "encoding/json" "reflect" "testing" "time" @@ -694,3 +695,20 @@ func TestStatRemoveExpiredQueue(t *testing.T) { t.Errorf("Expecting: 2, received: %+v", len(sq.SQItems)) } } + +func TestStatQueueJSONMarshall(t *testing.T) { + rply := new(StatQueue) + exp, err := NewStatQueue("cgrates.org", "STS", []*MetricWithFilters{ + {MetricID: utils.MetaASR}, + {MetricID: utils.MetaTCD}, + }, 1) + if err != nil { + t.Fatal(err) + } + if err = json.Unmarshal([]byte(utils.ToJSON(exp)), rply); err != nil { + t.Fatal(err) + } else if !reflect.DeepEqual(rply, exp) { + t.Errorf("Expected: %s , received: %s", utils.ToJSON(exp), utils.ToJSON(rply)) + } + +}