diff --git a/engine/libtrends.go b/engine/libtrends.go index ff0510419..74f414f7a 100644 --- a/engine/libtrends.go +++ b/engine/libtrends.go @@ -107,6 +107,9 @@ type Trend struct { // computeIndexes should be called after each retrieval from DB func (t *Trend) computeIndexes() { + t.mLast = make(map[string]time.Time) + t.mCounts = make(map[string]int) + t.mTotals = make(map[string]float64) for _, runTime := range t.RunTimes { for _, mWt := range t.Metrics[runTime] { t.indexesAppendMetric(mWt, runTime) diff --git a/engine/libtrends_test.go b/engine/libtrends_test.go new file mode 100644 index 000000000..f121c14f7 --- /dev/null +++ b/engine/libtrends_test.go @@ -0,0 +1,61 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package engine + +import ( + "sync" + "testing" + "time" + + "github.com/cgrates/cgrates/utils" +) + +func TestTrendGetTrendLabel(t *testing.T) { + now := time.Now() + t1 := now.Add(-2 * time.Second) + t2 := now.Add(-time.Second) + trnd1 := &Trend{ + RWMutex: sync.RWMutex{}, + Tenant: "cgrates.org", + ID: "TestTrendGetTrendLabel", + RunTimes: []time.Time{t1, t2, now}, + Metrics: map[time.Time]map[string]*MetricWithTrend{ + t1: {utils.MetaTCD: {utils.MetaTCD, float64(9 * time.Second), utils.NotAvailable}, utils.MetaTCC: {utils.MetaTCC, 9.0, utils.NotAvailable}}, + t2: {utils.MetaTCD: {utils.MetaTCD, float64(10 * time.Second), utils.MetaPositive}, utils.MetaTCC: {utils.MetaTCC, 10.0, utils.MetaPositive}}}, + } + trnd1.computeIndexes() + if lbl := trnd1.getTrendLabel(utils.MetaTCD, float64(11*time.Second), 0.0); lbl != utils.MetaPositive { + t.Errorf("Expecting: <%q> got <%q>", utils.MetaPositive, lbl) + } + if lbl := trnd1.getTrendLabel(utils.MetaTCD, float64(11*time.Second), 9.0); lbl != utils.MetaPositive { + t.Errorf("Expecting: <%q> got <%q>", utils.MetaPositive, lbl) + } + if lbl := trnd1.getTrendLabel(utils.MetaTCD, float64(11*time.Second), 10.0); lbl != utils.MetaConstant { + t.Errorf("Expecting: <%q> got <%q>", utils.MetaConstant, lbl) + } + if lbl := trnd1.getTrendLabel(utils.MetaTCD, float64(9*time.Second), 9.0); lbl != utils.MetaNegative { + t.Errorf("Expecting: <%q> got <%q>", utils.MetaNegative, lbl) + } + if lbl := trnd1.getTrendLabel(utils.MetaTCD, float64(9*time.Second), 10.0); lbl != utils.MetaConstant { + t.Errorf("Expecting: <%q> got <%q>", utils.MetaConstant, lbl) + } + if lbl := trnd1.getTrendLabel(utils.MetaACD, float64(9*time.Second), 0.0); lbl != utils.NotAvailable { + t.Errorf("Expecting: <%q> got <%q>", utils.NotAvailable, lbl) + } +} diff --git a/engine/trends.go b/engine/trends.go index 78f03a0b4..27ba2f46b 100644 --- a/engine/trends.go +++ b/engine/trends.go @@ -68,7 +68,7 @@ func (tS *TrendS) computeTrend(tP *TrendProfile) { if err := tS.connMgr.Call(context.Background(), tS.cgrcfg.TrendSCfg().StatSConns, utils.StatSv1GetQueueFloatMetrics, &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: tP.Tenant, ID: tP.StatID}}, - floatMetrics); err != nil { + &floatMetrics); err != nil { utils.Logger.Warning( fmt.Sprintf( "<%s> computing trend for with id: <%s:%s> stats <%s> error: <%s>", @@ -86,7 +86,7 @@ func (tS *TrendS) computeTrend(tP *TrendProfile) { } else if err != nil { utils.Logger.Warning( fmt.Sprintf( - "<%s> querying trend for with id: <%s:%s> dm error: <%s>", + "<%s> querying trend with id: <%s:%s> dm error: <%s>", utils.TrendS, tP.Tenant, tP.ID, err.Error())) return } @@ -104,7 +104,11 @@ func (tS *TrendS) computeTrend(tP *TrendProfile) { metricWithSettings = append(metricWithSettings, &MetricWithSettings{MetricID: mID}) } } + if len(metricWithSettings) == 0 { + return // nothing to compute + } trend.RunTimes = append(trend.RunTimes, now) + trend.Metrics[now] = make(map[string]*MetricWithTrend) for _, mWS := range metricWithSettings { mWt := &MetricWithTrend{ID: mWS.MetricID} var has bool @@ -114,9 +118,16 @@ func (tS *TrendS) computeTrend(tP *TrendProfile) { continue } mWt.Trend = trend.getTrendLabel(mWt.ID, mWt.Value, mWS.TrendSwingMargin) + trend.Metrics[now][mWt.ID] = mWt + } + if err := tS.dm.SetTrend(trend); err != nil { + utils.Logger.Warning( + fmt.Sprintf( + "<%s> setting trend with id: <%s:%s> dm error: <%s>", + utils.TrendS, tP.Tenant, tP.ID, err.Error())) + return } - return } // scheduleTrendQueries will schedule/re-schedule specific trend queries