mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-15 21:29:52 +05:00
Merge pull request #766 from TeoV/master
Add MinItems in Stat and update stats_it_test.go
This commit is contained in:
@@ -145,7 +145,7 @@ func testV1STSFromFolder(t *testing.T) {
|
||||
|
||||
func testV1STSGetStats(t *testing.T) {
|
||||
var reply []string
|
||||
expectedIDs := []string{"STATS_1"}
|
||||
expectedIDs := []string{"Stats1"}
|
||||
if err := stsV1Rpc.Call("StatSV1.GetQueueIDs", "cgrates.org", &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expectedIDs, reply) {
|
||||
@@ -184,6 +184,21 @@ func testV1STSProcessEvent(t *testing.T) {
|
||||
} else if reply != utils.OK {
|
||||
t.Errorf("received reply: %s", reply)
|
||||
}
|
||||
//process with one event (should be N/A becaus MinItems is 2)
|
||||
expectedMetrics := map[string]string{
|
||||
utils.MetaASR: utils.NOT_AVAILABLE,
|
||||
utils.MetaACD: utils.NOT_AVAILABLE,
|
||||
utils.MetaTCC: utils.NOT_AVAILABLE,
|
||||
utils.MetaTCD: utils.NOT_AVAILABLE,
|
||||
utils.MetaACC: utils.NOT_AVAILABLE,
|
||||
utils.MetaPDD: utils.NOT_AVAILABLE,
|
||||
}
|
||||
var metrics map[string]string
|
||||
if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "Stats1"}, &metrics); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expectedMetrics, metrics) {
|
||||
t.Errorf("expecting: %+v, received reply: %s", expectedMetrics, metrics)
|
||||
}
|
||||
ev2 := engine.StatEvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "event2",
|
||||
@@ -208,7 +223,7 @@ func testV1STSProcessEvent(t *testing.T) {
|
||||
} else if reply != utils.OK {
|
||||
t.Errorf("received reply: %s", reply)
|
||||
}
|
||||
expectedMetrics := map[string]string{
|
||||
expectedMetrics2 := map[string]string{
|
||||
utils.MetaASR: "66.66667%",
|
||||
utils.MetaACD: "1m30s",
|
||||
utils.MetaACC: "61.5",
|
||||
@@ -216,11 +231,11 @@ func testV1STSProcessEvent(t *testing.T) {
|
||||
utils.MetaTCC: "123",
|
||||
utils.MetaPDD: "4s",
|
||||
}
|
||||
var metrics map[string]string
|
||||
if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "STATS_1"}, &metrics); err != nil {
|
||||
var metrics2 map[string]string
|
||||
if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "Stats1"}, &metrics2); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expectedMetrics, metrics) {
|
||||
t.Errorf("expecting: %+v, received reply: %s", expectedMetrics, metrics)
|
||||
} else if !reflect.DeepEqual(expectedMetrics2, metrics2) {
|
||||
t.Errorf("expecting: %+v, received reply: %s", expectedMetrics2, metrics2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +250,7 @@ func testV1STSGetStatsAfterRestart(t *testing.T) {
|
||||
}
|
||||
var metrics map[string]string
|
||||
//get stats metrics before restart
|
||||
if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "STATS_1"}, &metrics); err != nil {
|
||||
if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "Stats1"}, &metrics); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expectedMetrics, metrics) {
|
||||
t.Errorf("expecting: %+v, received reply: %s", expectedMetrics, metrics)
|
||||
@@ -258,10 +273,10 @@ func testV1STSGetStatsAfterRestart(t *testing.T) {
|
||||
utils.MetaPDD: "4s",
|
||||
}
|
||||
var metrics2 map[string]string
|
||||
if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "STATS_1"}, &metrics2); err != nil {
|
||||
if err := stsV1Rpc.Call("StatSV1.GetQueueStringMetrics", &utils.TenantID{Tenant: "cgrates.org", ID: "Stats1"}, &metrics2); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expectedMetrics2, metrics2) {
|
||||
t.Errorf("expecting: %+v, received reply: %s", expectedMetrics2, metrics2)
|
||||
t.Errorf("After restat expecting: %+v, received reply: %s", expectedMetrics2, metrics2)
|
||||
}
|
||||
time.Sleep(time.Duration(1 * time.Second))
|
||||
}
|
||||
@@ -269,7 +284,7 @@ func testV1STSGetStatsAfterRestart(t *testing.T) {
|
||||
func testV1STSSetStatQueueProfile(t *testing.T) {
|
||||
var reply *engine.StatQueueProfile
|
||||
if err := stsV1Rpc.Call("ApierV1.GetStatQueueProfile",
|
||||
&utils.TenantID{"cgrates.org", "TEST_PROFILE1"}, &reply); err == nil ||
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "TEST_PROFILE1"}, &reply); err == nil ||
|
||||
err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -294,6 +309,7 @@ func testV1STSSetStatQueueProfile(t *testing.T) {
|
||||
Blocker: true,
|
||||
Stored: true,
|
||||
Weight: 20,
|
||||
MinItems: 1,
|
||||
}
|
||||
var result string
|
||||
if err := stsV1Rpc.Call("ApierV1.SetStatQueueProfile", statConfig, &result); err != nil {
|
||||
@@ -302,7 +318,7 @@ func testV1STSSetStatQueueProfile(t *testing.T) {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
if err := stsV1Rpc.Call("ApierV1.GetStatQueueProfile",
|
||||
&utils.TenantID{"cgrates.org", "TEST_PROFILE1"}, &reply); err != nil {
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "TEST_PROFILE1"}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(statConfig, reply) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", statConfig, reply)
|
||||
@@ -333,9 +349,10 @@ func testV1STSUpdateStatQueueProfile(t *testing.T) {
|
||||
} else if result != utils.OK {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
time.Sleep(time.Duration(1 * time.Second))
|
||||
var reply *engine.StatQueueProfile
|
||||
if err := stsV1Rpc.Call("ApierV1.GetStatQueueProfile",
|
||||
&utils.TenantID{statConfig.Tenant, statConfig.ID}, &reply); err != nil {
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "TEST_PROFILE1"}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(statConfig, reply) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", statConfig, reply)
|
||||
@@ -345,14 +362,14 @@ func testV1STSUpdateStatQueueProfile(t *testing.T) {
|
||||
func testV1STSRemoveStatQueueProfile(t *testing.T) {
|
||||
var resp string
|
||||
if err := stsV1Rpc.Call("ApierV1.RemStatQueueProfile",
|
||||
&utils.TenantID{statConfig.Tenant, statConfig.ID}, &resp); err != nil {
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "TEST_PROFILE1"}, &resp); err != nil {
|
||||
t.Error(err)
|
||||
} else if resp != utils.OK {
|
||||
t.Error("Unexpected reply returned", resp)
|
||||
}
|
||||
var sqp *engine.StatQueueProfile
|
||||
if err := stsV1Rpc.Call("ApierV1.GetStatQueueProfile",
|
||||
&utils.TenantID{statConfig.Tenant, statConfig.ID}, sqp); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "TEST_PROFILE1"}, &sqp); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (self *ApierV1) GetTPStatIDs(attrs AttrGetTPStatIds, reply *[]string) error
|
||||
if missing := utils.MissingStructFields(&attrs, []string{"TPid"}); len(missing) != 0 { //Params missing
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
if ids, err := self.StorDb.GetTpTableIds(attrs.TPid, utils.TBLTPStats, utils.TPDistinctIds{"tag"}, nil, &attrs.Paginator); err != nil {
|
||||
if ids, err := self.StorDb.GetTpTableIds(attrs.TPid, utils.TBLTPStats, utils.TPDistinctIds{"id"}, nil, &attrs.Paginator); err != nil {
|
||||
if err.Error() != utils.ErrNotFound.Error() {
|
||||
err = utils.NewErrServerError(err)
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func (self *ApierV1) RemTPStat(attrs AttrGetTPStat, reply *string) error {
|
||||
if missing := utils.MissingStructFields(&attrs, []string{"TPid", "ID"}); len(missing) != 0 { //Params missing
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
if err := self.StorDb.RemTpData(utils.TBLTPStats, attrs.TPid, map[string]string{"tag": attrs.ID}); err != nil {
|
||||
if err := self.StorDb.RemTpData(utils.TBLTPStats, attrs.TPid, map[string]string{"id": attrs.ID}); err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
} else {
|
||||
*reply = utils.OK
|
||||
|
||||
@@ -146,6 +146,7 @@ func testTPStatsSetTPStat(t *testing.T) {
|
||||
Blocker: false,
|
||||
Stored: false,
|
||||
Weight: 20,
|
||||
MinItems: 1,
|
||||
Thresholds: []string{"ThreshValue", "ThreshValueTwo"},
|
||||
}
|
||||
var result string
|
||||
|
||||
@@ -424,10 +424,10 @@ CREATE TABLE tp_resources (
|
||||
|
||||
DROP TABLE IF EXISTS tp_stats;
|
||||
CREATE TABLE tp_stats (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`pk` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`tpid` varchar(64) NOT NULL,
|
||||
`tenant` varchar(64) NOT NULL,
|
||||
`tag` varchar(64) NOT NULL,
|
||||
`id` varchar(64) NOT NULL,
|
||||
`filter_type` varchar(16) NOT NULL,
|
||||
`filter_field_name` varchar(64) NOT NULL,
|
||||
`filter_field_values` varchar(256) NOT NULL,
|
||||
@@ -438,11 +438,12 @@ CREATE TABLE tp_stats (
|
||||
`blocker` BOOLEAN NOT NULL,
|
||||
`stored` BOOLEAN NOT NULL,
|
||||
`weight` decimal(8,2) NOT NULL,
|
||||
`min_items` int(11) NOT NULL,
|
||||
`thresholds` varchar(64) NOT NULL,
|
||||
`created_at` TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
PRIMARY KEY (`pk`),
|
||||
KEY `tpid` (`tpid`),
|
||||
UNIQUE KEY `unique_tp_stats` (`tpid`, `tenant`, `tag`, `filter_type`, `filter_field_name`)
|
||||
UNIQUE KEY `unique_tp_stats` (`tpid`, `tenant`, `id`, `filter_type`, `filter_field_name`)
|
||||
);
|
||||
|
||||
--
|
||||
@@ -451,10 +452,10 @@ CREATE TABLE tp_stats (
|
||||
|
||||
DROP TABLE IF EXISTS tp_thresholds;
|
||||
CREATE TABLE tp_thresholds (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`pk` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`tpid` varchar(64) NOT NULL,
|
||||
`tenant` varchar(64) NOT NULL,
|
||||
`tag` varchar(64) NOT NULL,
|
||||
`id` varchar(64) NOT NULL,
|
||||
`filter_type` varchar(16) NOT NULL,
|
||||
`filter_field_name` varchar(64) NOT NULL,
|
||||
`filter_field_values` varchar(256) NOT NULL,
|
||||
@@ -465,9 +466,9 @@ CREATE TABLE tp_thresholds (
|
||||
`weight` decimal(8,2) NOT NULL,
|
||||
`action_ids` varchar(64) NOT NULL,
|
||||
`created_at` TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
PRIMARY KEY (`pk`),
|
||||
KEY `tpid` (`tpid`),
|
||||
UNIQUE KEY `unique_tp_thresholds` (`tpid`, `tag`, `filter_type`, `filter_field_name`)
|
||||
UNIQUE KEY `unique_tp_thresholds` (`tpid`,`tenant`, `id`, `filter_type`, `filter_field_name`)
|
||||
);
|
||||
|
||||
--
|
||||
|
||||
@@ -420,10 +420,10 @@ CREATE INDEX tp_resources_unique ON tp_resources ("tpid", "tenant", "id", "fil
|
||||
|
||||
DROP TABLE IF EXISTS tp_stats;
|
||||
CREATE TABLE tp_stats (
|
||||
"id" SERIAL PRIMARY KEY,
|
||||
"pk" SERIAL PRIMARY KEY,
|
||||
"tpid" varchar(64) NOT NULL,
|
||||
"tenant"varchar(64) NOT NULL,
|
||||
"tag" varchar(64) NOT NULL,
|
||||
"id" varchar(64) NOT NULL,
|
||||
"filter_type" varchar(16) NOT NULL,
|
||||
"filter_field_name" varchar(64) NOT NULL,
|
||||
"filter_field_values" varchar(256) NOT NULL,
|
||||
@@ -434,11 +434,12 @@ CREATE TABLE tp_stats (
|
||||
"blocker" BOOLEAN NOT NULL,
|
||||
"stored" BOOLEAN NOT NULL,
|
||||
"weight" decimal(8,2) NOT NULL,
|
||||
"min_items" INTEGER NOT NULL,
|
||||
"thresholds" varchar(64) NOT NULL,
|
||||
"created_at" TIMESTAMP WITH TIME ZONE
|
||||
);
|
||||
CREATE INDEX tp_stats_idx ON tp_stats (tpid);
|
||||
CREATE INDEX tp_stats_unique ON tp_stats ("tpid","tenant", "tag", "filter_type", "filter_field_name");
|
||||
CREATE INDEX tp_stats_unique ON tp_stats ("tpid","tenant", "id", "filter_type", "filter_field_name");
|
||||
|
||||
--
|
||||
-- Table structure for table `tp_threshold_cfgs`
|
||||
@@ -446,10 +447,10 @@ CREATE INDEX tp_stats_unique ON tp_stats ("tpid","tenant", "tag", "filter_type"
|
||||
|
||||
DROP TABLE IF EXISTS tp_thresholds;
|
||||
CREATE TABLE tp_thresholds (
|
||||
"id" SERIAL PRIMARY KEY,
|
||||
"pk" SERIAL PRIMARY KEY,
|
||||
"tpid" varchar(64) NOT NULL,
|
||||
"tenant"varchar(64) NOT NULL,
|
||||
"tag" varchar(64) NOT NULL,
|
||||
"id" varchar(64) NOT NULL,
|
||||
"filter_type" varchar(16) NOT NULL,
|
||||
"filter_field_name" varchar(64) NOT NULL,
|
||||
"filter_field_values" varchar(256) NOT NULL,
|
||||
@@ -462,7 +463,7 @@ CREATE TABLE tp_thresholds (
|
||||
"created_at" TIMESTAMP WITH TIME ZONE
|
||||
);
|
||||
CREATE INDEX tp_thresholds_idx ON tp_thresholds (tpid);
|
||||
CREATE INDEX tp_thresholds_unique ON tp_thresholds ("tpid", "tag", "filter_type", "filter_field_name");
|
||||
CREATE INDEX tp_thresholds_unique ON tp_thresholds ("tpid","tenant", "id", "filter_type", "filter_field_name");
|
||||
|
||||
|
||||
--
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],QueueLength[6],TTL[7],Metrics[8],Blocker[9],Stored[10],Weight[11],Thresholds[12]
|
||||
cgrates.org,Stats1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acd;*acc;*tcd;*tcc;*pdd,true,true,20,THRESH1;THRESH2
|
||||
#Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],QueueLength[6],TTL[7],Metrics[8],Blocker[9],Stored[10],Weight[11],MinItems[12],Thresholds[13]
|
||||
cgrates.org,Stats1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acc;*tcc;*acd;*tcd;*pdd,true,true,20,2,THRESH1;THRESH2
|
||||
|
||||
|
@@ -1,3 +1,2 @@
|
||||
#Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],QueueLength[6],TTL[7],Metrics[8],Blocker[9],Stored[10],Weight[11],MinItems[12],Thresholds[13]
|
||||
cgrates.org,STATS_1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acc;*tcc;*acd;*tcd;*pdd,true,true,20,THRESH1;THRESH2
|
||||
|
||||
cgrates.org,Stats1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acc;*tcc;*acd;*tcd;*pdd,true,true,20,2,THRESH1;THRESH2
|
||||
|
||||
|
@@ -40,6 +40,7 @@ type StatQueueProfile struct {
|
||||
Blocker bool // blocker flag to stop processing on filters matched
|
||||
Stored bool
|
||||
Weight float64
|
||||
MinItems int
|
||||
}
|
||||
|
||||
func (sqp *StatQueueProfile) TenantID() string {
|
||||
@@ -154,6 +155,7 @@ func NewStoredStatQueue(sq *StatQueue, ms Marshaler) (sSQ *StoredStatQueue, err
|
||||
ExpiryTime *time.Time
|
||||
}, len(sq.SQItems)),
|
||||
SQMetrics: make(map[string][]byte, len(sq.SQMetrics)),
|
||||
MinItems: sq.MinItems,
|
||||
}
|
||||
for i, sqItm := range sq.SQItems {
|
||||
sSQ.SQItems[i] = sqItm
|
||||
@@ -177,6 +179,7 @@ type StoredStatQueue struct {
|
||||
ExpiryTime *time.Time // Used to auto-expire events
|
||||
}
|
||||
SQMetrics map[string][]byte
|
||||
MinItems int
|
||||
}
|
||||
|
||||
// SqID will compose the unique identifier for the StatQueue out of Tenant and ID
|
||||
@@ -194,12 +197,13 @@ func (ssq *StoredStatQueue) AsStatQueue(ms Marshaler) (sq *StatQueue, err error)
|
||||
ExpiryTime *time.Time
|
||||
}, len(ssq.SQItems)),
|
||||
SQMetrics: make(map[string]StatMetric, len(ssq.SQMetrics)),
|
||||
MinItems: ssq.MinItems,
|
||||
}
|
||||
for i, sqItm := range ssq.SQItems {
|
||||
sq.SQItems[i] = sqItm
|
||||
}
|
||||
for metricID, marshaled := range ssq.SQMetrics {
|
||||
if metric, err := NewStatMetric(metricID); err != nil {
|
||||
if metric, err := NewStatMetric(metricID, ssq.MinItems); err != nil {
|
||||
return nil, err
|
||||
} else if err := metric.LoadMarshaled(ms, marshaled); err != nil {
|
||||
return nil, err
|
||||
@@ -219,6 +223,7 @@ type StatQueue struct {
|
||||
ExpiryTime *time.Time // Used to auto-expire events
|
||||
}
|
||||
SQMetrics map[string]StatMetric
|
||||
MinItems int
|
||||
sqPrfl *StatQueueProfile
|
||||
dirty *bool // needs save
|
||||
ttl *time.Duration // timeToLeave, picked on each init
|
||||
|
||||
@@ -273,8 +273,8 @@ cgrates.org,ResGroup21,*rsr_fields,,HdrSubject(~^1.*1$);HdrDestination(1002),,,,
|
||||
cgrates.org,ResGroup22,*destinations,HdrDestination,DST_FS,2014-07-29T15:00:00Z,3600s,2,premium_call,true,true,10,
|
||||
`
|
||||
stats = `
|
||||
#Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],QueueLength[6],TTL[7],Metrics[8],Blocker[9],Stored[10],Weight[11],Thresholds[12]
|
||||
cgrates.org,Stats1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acd,true,true,20,THRESH1;THRESH2
|
||||
#Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],QueueLength[6],TTL[7],Metrics[8],Blocker[9],Stored[10],Weight[11],MinItems[12],Thresholds[13]
|
||||
cgrates.org,Stats1,*string,Account,1001;1002,2014-07-29T15:00:00Z,100,1s,*asr;*acc;*tcc;*acd;*tcd;*pdd,true,true,20,2,THRESH1;THRESH2
|
||||
`
|
||||
|
||||
thresholds = `
|
||||
@@ -1452,11 +1452,12 @@ func TestLoadStats(t *testing.T) {
|
||||
},
|
||||
QueueLength: 100,
|
||||
TTL: "1s",
|
||||
Metrics: []string{"*asr", "*acd"},
|
||||
Metrics: []string{"*asr", "*acc", "*tcc", "*acd", "*tcd", "*pdd"},
|
||||
Thresholds: []string{"THRESH1", "THRESH2"},
|
||||
Blocker: true,
|
||||
Stored: true,
|
||||
Weight: 20,
|
||||
MinItems: 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1966,14 +1966,15 @@ type TpStatsS []*TpStats
|
||||
func (tps TpStatsS) AsTPStats() (result []*utils.TPStats) {
|
||||
mst := make(map[string]*utils.TPStats)
|
||||
for _, tp := range tps {
|
||||
st, found := mst[tp.Tag]
|
||||
st, found := mst[tp.ID]
|
||||
if !found {
|
||||
st = &utils.TPStats{
|
||||
Tenant: tp.Tenant,
|
||||
TPid: tp.Tpid,
|
||||
ID: tp.Tag,
|
||||
Blocker: tp.Blocker,
|
||||
Stored: tp.Stored,
|
||||
Tenant: tp.Tenant,
|
||||
TPid: tp.Tpid,
|
||||
ID: tp.ID,
|
||||
Blocker: tp.Blocker,
|
||||
Stored: tp.Stored,
|
||||
MinItems: tp.MinItems,
|
||||
}
|
||||
}
|
||||
if tp.Blocker == false || tp.Blocker == true {
|
||||
@@ -1982,7 +1983,9 @@ func (tps TpStatsS) AsTPStats() (result []*utils.TPStats) {
|
||||
if tp.Stored == false || tp.Stored == true {
|
||||
st.Stored = tp.Stored
|
||||
}
|
||||
|
||||
if tp.MinItems != 0 {
|
||||
st.MinItems = tp.MinItems
|
||||
}
|
||||
if tp.QueueLength != 0 {
|
||||
st.QueueLength = tp.QueueLength
|
||||
}
|
||||
@@ -2020,7 +2023,7 @@ func (tps TpStatsS) AsTPStats() (result []*utils.TPStats) {
|
||||
FieldName: tp.FilterFieldName,
|
||||
Values: strings.Split(tp.FilterFieldValues, utils.INFIELD_SEP)})
|
||||
}
|
||||
mst[tp.Tag] = st
|
||||
mst[tp.ID] = st
|
||||
}
|
||||
result = make([]*utils.TPStats, len(mst))
|
||||
i := 0
|
||||
@@ -2037,9 +2040,10 @@ func APItoModelStats(st *utils.TPStats) (mdls TpStatsS) {
|
||||
}
|
||||
for i, fltr := range st.Filters {
|
||||
mdl := &TpStats{
|
||||
Tenant: st.Tenant,
|
||||
Tpid: st.TPid,
|
||||
Tag: st.ID,
|
||||
Tenant: st.Tenant,
|
||||
Tpid: st.TPid,
|
||||
ID: st.ID,
|
||||
MinItems: st.MinItems,
|
||||
}
|
||||
if i == 0 {
|
||||
mdl.TTL = st.TTL
|
||||
@@ -2047,6 +2051,7 @@ func APItoModelStats(st *utils.TPStats) (mdls TpStatsS) {
|
||||
mdl.Stored = st.Stored
|
||||
mdl.Weight = st.Weight
|
||||
mdl.QueueLength = st.QueueLength
|
||||
mdl.MinItems = st.MinItems
|
||||
for i, val := range st.Metrics {
|
||||
if i != 0 {
|
||||
mdl.Metrics += utils.INFIELD_SEP
|
||||
@@ -2089,6 +2094,7 @@ func APItoStats(tpST *utils.TPStats, timezone string) (st *StatQueueProfile, err
|
||||
Weight: tpST.Weight,
|
||||
Blocker: tpST.Blocker,
|
||||
Stored: tpST.Stored,
|
||||
MinItems: tpST.MinItems,
|
||||
Filters: make([]*RequestFilter, len(tpST.Filters)),
|
||||
}
|
||||
if tpST.TTL != "" {
|
||||
@@ -2123,12 +2129,12 @@ type TpThresholdS []*TpThreshold
|
||||
func (tps TpThresholdS) AsTPThreshold() (result []*utils.TPThreshold) {
|
||||
mst := make(map[string]*utils.TPThreshold)
|
||||
for _, tp := range tps {
|
||||
th, found := mst[tp.Tag]
|
||||
th, found := mst[tp.ID]
|
||||
if !found {
|
||||
th = &utils.TPThreshold{
|
||||
TPid: tp.Tpid,
|
||||
Tenant: tp.Tenant,
|
||||
ID: tp.Tag,
|
||||
ID: tp.ID,
|
||||
Blocker: tp.Blocker,
|
||||
Recurrent: tp.Recurrent,
|
||||
MinSleep: tp.MinSleep,
|
||||
@@ -2156,7 +2162,7 @@ func (tps TpThresholdS) AsTPThreshold() (result []*utils.TPThreshold) {
|
||||
FieldName: tp.FilterFieldName,
|
||||
Values: strings.Split(tp.FilterFieldValues, utils.INFIELD_SEP)})
|
||||
}
|
||||
mst[tp.Tag] = th
|
||||
mst[tp.ID] = th
|
||||
}
|
||||
result = make([]*utils.TPThreshold, len(mst))
|
||||
i := 0
|
||||
@@ -2174,7 +2180,7 @@ func APItoModelTPThreshold(th *utils.TPThreshold) (mdls TpThresholdS) {
|
||||
for i, fltr := range th.Filters {
|
||||
mdl := &TpThreshold{
|
||||
Tpid: th.TPid,
|
||||
Tag: th.ID,
|
||||
ID: th.ID,
|
||||
}
|
||||
if i == 0 {
|
||||
mdl.Blocker = th.Blocker
|
||||
|
||||
@@ -846,13 +846,14 @@ func TestTPStatsAsTPStats(t *testing.T) {
|
||||
tps := []*TpStats{
|
||||
&TpStats{
|
||||
Tpid: "TEST_TPID",
|
||||
Tag: "Stats1",
|
||||
ID: "Stats1",
|
||||
FilterType: MetaStringPrefix,
|
||||
FilterFieldName: "Account",
|
||||
FilterFieldValues: "1001;1002",
|
||||
ActivationInterval: "2014-07-29T15:00:00Z",
|
||||
QueueLength: 100,
|
||||
TTL: "1s",
|
||||
MinItems: 1,
|
||||
Metrics: "*asr;*acd;*acc",
|
||||
Thresholds: "THRESH1;THRESH2",
|
||||
Stored: false,
|
||||
@@ -863,7 +864,7 @@ func TestTPStatsAsTPStats(t *testing.T) {
|
||||
eTPs := []*utils.TPStats{
|
||||
&utils.TPStats{
|
||||
TPid: tps[0].Tpid,
|
||||
ID: tps[0].Tag,
|
||||
ID: tps[0].ID,
|
||||
Filters: []*utils.TPRequestFilter{
|
||||
&utils.TPRequestFilter{
|
||||
Type: tps[0].FilterType,
|
||||
@@ -877,6 +878,7 @@ func TestTPStatsAsTPStats(t *testing.T) {
|
||||
QueueLength: tps[0].QueueLength,
|
||||
TTL: tps[0].TTL,
|
||||
Metrics: []string{"*asr", "*acd", "*acc"},
|
||||
MinItems: tps[0].MinItems,
|
||||
Thresholds: []string{"THRESH1", "THRESH2"},
|
||||
Stored: tps[0].Stored,
|
||||
Blocker: tps[0].Blocker,
|
||||
@@ -900,6 +902,7 @@ func TestAPItoTPStats(t *testing.T) {
|
||||
QueueLength: 100,
|
||||
TTL: "1s",
|
||||
Metrics: []string{"*asr", "*acd", "*acc"},
|
||||
MinItems: 1,
|
||||
Thresholds: []string{"THRESH1", "THRESH2"},
|
||||
Stored: false,
|
||||
Blocker: false,
|
||||
@@ -914,6 +917,7 @@ func TestAPItoTPStats(t *testing.T) {
|
||||
Stored: tps.Stored,
|
||||
Blocker: tps.Blocker,
|
||||
Weight: 20.0,
|
||||
MinItems: tps.MinItems,
|
||||
}
|
||||
if eTPs.TTL, err = utils.ParseDurationWithSecs(tps.TTL); err != nil {
|
||||
t.Errorf("Got error: %+v", err)
|
||||
@@ -935,7 +939,7 @@ func TestAsTPThresholdAsAsTPThreshold(t *testing.T) {
|
||||
tps := []*TpThreshold{
|
||||
&TpThreshold{
|
||||
Tpid: "TEST_TPID",
|
||||
Tag: "Stats1",
|
||||
ID: "Stats1",
|
||||
FilterType: MetaStringPrefix,
|
||||
FilterFieldName: "Account",
|
||||
FilterFieldValues: "1001;1002",
|
||||
@@ -950,7 +954,7 @@ func TestAsTPThresholdAsAsTPThreshold(t *testing.T) {
|
||||
eTPs := []*utils.TPThreshold{
|
||||
&utils.TPThreshold{
|
||||
TPid: tps[0].Tpid,
|
||||
ID: tps[0].Tag,
|
||||
ID: tps[0].ID,
|
||||
Filters: []*utils.TPRequestFilter{
|
||||
&utils.TPRequestFilter{
|
||||
Type: tps[0].FilterType,
|
||||
|
||||
@@ -481,10 +481,10 @@ func (t TBLVersion) TableName() string {
|
||||
}
|
||||
|
||||
type TpStats struct {
|
||||
ID int64
|
||||
PK uint `gorm:"primary_key"`
|
||||
Tpid string
|
||||
Tenant string `index:"0" re:""`
|
||||
Tag string `index:"1" re:""`
|
||||
ID string `index:"1" re:""`
|
||||
FilterType string `index:"2" re:"^\*[A-Za-z].*"`
|
||||
FilterFieldName string `index:"3" re:""`
|
||||
FilterFieldValues string `index:"4" re:""`
|
||||
@@ -495,15 +495,16 @@ type TpStats struct {
|
||||
Blocker bool `index:"9" re:""`
|
||||
Stored bool `index:"10" re:""`
|
||||
Weight float64 `index:"11" re:"\d+\.?\d*"`
|
||||
Thresholds string `index:"12" re:""`
|
||||
MinItems int `index:"12" re:""`
|
||||
Thresholds string `index:"13" re:""`
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type TpThreshold struct {
|
||||
ID int64
|
||||
PK uint `gorm:"primary_key"`
|
||||
Tpid string
|
||||
Tenant string `index:"0" re:""`
|
||||
Tag string `index:"1" re:""`
|
||||
ID string `index:"1" re:""`
|
||||
FilterType string `index:"2" re:"^\*[A-Za-z].*"`
|
||||
FilterFieldName string `index:"3" re:""`
|
||||
FilterFieldValues string `index:"4" re:""`
|
||||
|
||||
@@ -28,8 +28,8 @@ import (
|
||||
|
||||
// NewStatMetric instantiates the StatMetric
|
||||
// cfg serves as general purpose container to pass config options to metric
|
||||
func NewStatMetric(metricID string) (sm StatMetric, err error) {
|
||||
metrics := map[string]func() (StatMetric, error){
|
||||
func NewStatMetric(metricID string, minItems int) (sm StatMetric, err error) {
|
||||
metrics := map[string]func(int) (StatMetric, error){
|
||||
utils.MetaASR: NewASR,
|
||||
utils.MetaACD: NewACD,
|
||||
utils.MetaTCD: NewTCD,
|
||||
@@ -41,7 +41,7 @@ func NewStatMetric(metricID string) (sm StatMetric, err error) {
|
||||
if _, has := metrics[metricID]; !has {
|
||||
return nil, fmt.Errorf("unsupported metric: %s", metricID)
|
||||
}
|
||||
return metrics[metricID]()
|
||||
return metrics[metricID](minItems)
|
||||
}
|
||||
|
||||
// StatMetric is the interface which a metric should implement
|
||||
@@ -55,8 +55,8 @@ type StatMetric interface {
|
||||
LoadMarshaled(ms Marshaler, marshaled []byte) (err error)
|
||||
}
|
||||
|
||||
func NewASR() (StatMetric, error) {
|
||||
return &StatASR{Events: make(map[string]bool)}, nil
|
||||
func NewASR(minItems int) (StatMetric, error) {
|
||||
return &StatASR{Events: make(map[string]bool), MinItems: minItems}, nil
|
||||
}
|
||||
|
||||
// ASR implements AverageSuccessRatio metric
|
||||
@@ -64,14 +64,15 @@ type StatASR struct {
|
||||
Answered float64
|
||||
Count float64
|
||||
Events map[string]bool // map[EventTenantID]Answered
|
||||
val *float64 // cached ASR value
|
||||
MinItems int
|
||||
val *float64 // cached ASR value
|
||||
}
|
||||
|
||||
// getValue returns asr.val
|
||||
func (asr *StatASR) getValue() float64 {
|
||||
if asr.val == nil {
|
||||
if asr.Count == 0 {
|
||||
asr.val = utils.Float64Pointer(float64(STATS_NA))
|
||||
if (asr.MinItems > 0 && len(asr.Events) < asr.MinItems) || (asr.Count == 0) {
|
||||
asr.val = utils.Float64Pointer(STATS_NA)
|
||||
} else {
|
||||
asr.val = utils.Float64Pointer(utils.Round((asr.Answered / asr.Count * 100),
|
||||
config.CgrConfig().RoundingDecimals, utils.ROUNDING_MIDDLE))
|
||||
@@ -86,10 +87,12 @@ func (asr *StatASR) GetValue() (v interface{}) {
|
||||
}
|
||||
|
||||
func (asr *StatASR) GetStringValue(fmtOpts string) (valStr string) {
|
||||
if asr.Count == 0 {
|
||||
return utils.NOT_AVAILABLE
|
||||
if val := asr.getValue(); val == STATS_NA {
|
||||
valStr = utils.NOT_AVAILABLE
|
||||
} else {
|
||||
valStr = fmt.Sprintf("%v%%", asr.getValue())
|
||||
}
|
||||
return fmt.Sprintf("%v%%", asr.getValue()) // %v will automatically limit the number of decimals printed
|
||||
return
|
||||
}
|
||||
|
||||
// GetFloat64Value is part of StatMetric interface
|
||||
@@ -139,22 +142,23 @@ func (asr *StatASR) LoadMarshaled(ms Marshaler, marshaled []byte) (err error) {
|
||||
return ms.Unmarshal(marshaled, asr)
|
||||
}
|
||||
|
||||
func NewACD() (StatMetric, error) {
|
||||
return &StatACD{Events: make(map[string]time.Duration)}, nil
|
||||
func NewACD(minItems int) (StatMetric, error) {
|
||||
return &StatACD{Events: make(map[string]time.Duration), MinItems: minItems}, nil
|
||||
}
|
||||
|
||||
// ACD implements AverageCallDuration metric
|
||||
type StatACD struct {
|
||||
Sum time.Duration
|
||||
Count int64
|
||||
Events map[string]time.Duration // map[EventTenantID]Duration
|
||||
val *time.Duration // cached ACD value
|
||||
Sum time.Duration
|
||||
Count int64
|
||||
Events map[string]time.Duration // map[EventTenantID]Duration
|
||||
MinItems int
|
||||
val *time.Duration // cached ACD value
|
||||
}
|
||||
|
||||
// getValue returns acr.val
|
||||
func (acd *StatACD) getValue() time.Duration {
|
||||
if acd.val == nil {
|
||||
if acd.Count == 0 {
|
||||
if (acd.MinItems > 0 && len(acd.Events) < acd.MinItems) || (acd.Count == 0) {
|
||||
acd.val = utils.DurationPointer(time.Duration((-1) * time.Nanosecond))
|
||||
} else {
|
||||
acd.val = utils.DurationPointer(time.Duration(acd.Sum.Nanoseconds() / acd.Count))
|
||||
@@ -163,11 +167,13 @@ func (acd *StatACD) getValue() time.Duration {
|
||||
return *acd.val
|
||||
}
|
||||
|
||||
func (acd *StatACD) GetStringValue(fmtOpts string) (val string) {
|
||||
if acd.Count == 0 {
|
||||
return utils.NOT_AVAILABLE
|
||||
func (acd *StatACD) GetStringValue(fmtOpts string) (valStr string) {
|
||||
if val := acd.getValue(); val == time.Duration((-1)*time.Nanosecond) {
|
||||
valStr = utils.NOT_AVAILABLE
|
||||
} else {
|
||||
valStr = fmt.Sprintf("%+v", acd.getValue())
|
||||
}
|
||||
return fmt.Sprintf("%+v", acd.getValue())
|
||||
return
|
||||
}
|
||||
|
||||
func (acd *StatACD) GetValue() (v interface{}) {
|
||||
@@ -175,10 +181,12 @@ func (acd *StatACD) GetValue() (v interface{}) {
|
||||
}
|
||||
|
||||
func (acd *StatACD) GetFloat64Value() (v float64) {
|
||||
if acd.Count == 0 {
|
||||
return -1.0
|
||||
if val := acd.getValue(); val == time.Duration((-1)*time.Nanosecond) {
|
||||
v = -1.0
|
||||
} else {
|
||||
v = acd.getValue().Seconds()
|
||||
}
|
||||
return acd.getValue().Seconds()
|
||||
return
|
||||
}
|
||||
|
||||
func (acd *StatACD) AddEvent(ev *StatEvent) (err error) {
|
||||
@@ -221,22 +229,23 @@ func (acd *StatACD) LoadMarshaled(ms Marshaler, marshaled []byte) (err error) {
|
||||
return ms.Unmarshal(marshaled, acd)
|
||||
}
|
||||
|
||||
func NewTCD() (StatMetric, error) {
|
||||
return &StatTCD{Events: make(map[string]time.Duration)}, nil
|
||||
func NewTCD(minItems int) (StatMetric, error) {
|
||||
return &StatTCD{Events: make(map[string]time.Duration), MinItems: minItems}, nil
|
||||
}
|
||||
|
||||
// TCD implements TotalCallDuration metric
|
||||
type StatTCD struct {
|
||||
Sum time.Duration
|
||||
Count int64
|
||||
Events map[string]time.Duration // map[EventTenantID]Duration
|
||||
val *time.Duration // cached TCD value
|
||||
Sum time.Duration
|
||||
Count int64
|
||||
Events map[string]time.Duration // map[EventTenantID]Duration
|
||||
MinItems int
|
||||
val *time.Duration // cached TCD value
|
||||
}
|
||||
|
||||
// getValue returns tcd.val
|
||||
func (tcd *StatTCD) getValue() time.Duration {
|
||||
if tcd.val == nil {
|
||||
if tcd.Count == 0 {
|
||||
if (tcd.MinItems > 0 && len(tcd.Events) < tcd.MinItems) || (tcd.Count == 0) {
|
||||
tcd.val = utils.DurationPointer(time.Duration((-1) * time.Nanosecond))
|
||||
} else {
|
||||
tcd.val = utils.DurationPointer(time.Duration(tcd.Sum.Nanoseconds()))
|
||||
@@ -245,11 +254,13 @@ func (tcd *StatTCD) getValue() time.Duration {
|
||||
return *tcd.val
|
||||
}
|
||||
|
||||
func (tcd *StatTCD) GetStringValue(fmtOpts string) (val string) {
|
||||
if tcd.Count == 0 {
|
||||
return utils.NOT_AVAILABLE
|
||||
func (tcd *StatTCD) GetStringValue(fmtOpts string) (valStr string) {
|
||||
if val := tcd.getValue(); val == time.Duration((-1)*time.Nanosecond) {
|
||||
valStr = utils.NOT_AVAILABLE
|
||||
} else {
|
||||
valStr = fmt.Sprintf("%+v", tcd.getValue())
|
||||
}
|
||||
return fmt.Sprintf("%+v", tcd.getValue())
|
||||
return
|
||||
}
|
||||
|
||||
func (tcd *StatTCD) GetValue() (v interface{}) {
|
||||
@@ -257,10 +268,12 @@ func (tcd *StatTCD) GetValue() (v interface{}) {
|
||||
}
|
||||
|
||||
func (tcd *StatTCD) GetFloat64Value() (v float64) {
|
||||
if tcd.Count == 0 {
|
||||
return -1.0
|
||||
if val := tcd.getValue(); val == time.Duration((-1)*time.Nanosecond) {
|
||||
v = -1.0
|
||||
} else {
|
||||
v = tcd.getValue().Seconds()
|
||||
}
|
||||
return tcd.getValue().Seconds()
|
||||
return
|
||||
}
|
||||
|
||||
func (tcd *StatTCD) AddEvent(ev *StatEvent) (err error) {
|
||||
@@ -305,23 +318,24 @@ func (tcd *StatTCD) LoadMarshaled(ms Marshaler, marshaled []byte) (err error) {
|
||||
return ms.Unmarshal(marshaled, tcd)
|
||||
}
|
||||
|
||||
func NewACC() (StatMetric, error) {
|
||||
return &StatACC{Events: make(map[string]float64)}, nil
|
||||
func NewACC(minItems int) (StatMetric, error) {
|
||||
return &StatACC{Events: make(map[string]float64), MinItems: minItems}, nil
|
||||
}
|
||||
|
||||
// ACC implements AverageCallCost metric
|
||||
type StatACC struct {
|
||||
Sum float64
|
||||
Count float64
|
||||
Events map[string]float64 // map[EventTenantID]Cost
|
||||
val *float64 // cached ACC value
|
||||
Sum float64
|
||||
Count float64
|
||||
Events map[string]float64 // map[EventTenantID]Cost
|
||||
MinItems int
|
||||
val *float64 // cached ACC value
|
||||
}
|
||||
|
||||
// getValue returns tcd.val
|
||||
func (acc *StatACC) getValue() float64 {
|
||||
if acc.val == nil {
|
||||
if acc.Count == 0 {
|
||||
acc.val = utils.Float64Pointer(float64(STATS_NA))
|
||||
if (acc.MinItems > 0 && len(acc.Events) < acc.MinItems) || (acc.Count == 0) {
|
||||
acc.val = utils.Float64Pointer(STATS_NA)
|
||||
} else {
|
||||
acc.val = utils.Float64Pointer(utils.Round((acc.Sum / acc.Count),
|
||||
config.CgrConfig().RoundingDecimals, utils.ROUNDING_MIDDLE))
|
||||
@@ -330,11 +344,13 @@ func (acc *StatACC) getValue() float64 {
|
||||
return *acc.val
|
||||
}
|
||||
|
||||
func (acc *StatACC) GetStringValue(fmtOpts string) (val string) {
|
||||
if acc.Count == 0 {
|
||||
return utils.NOT_AVAILABLE
|
||||
func (acc *StatACC) GetStringValue(fmtOpts string) (valStr string) {
|
||||
if val := acc.getValue(); val == STATS_NA {
|
||||
valStr = utils.NOT_AVAILABLE
|
||||
} else {
|
||||
valStr = strconv.FormatFloat(acc.getValue(), 'f', -1, 64)
|
||||
}
|
||||
return strconv.FormatFloat(acc.getValue(), 'f', -1, 64)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
@@ -387,23 +403,24 @@ func (acc *StatACC) LoadMarshaled(ms Marshaler, marshaled []byte) (err error) {
|
||||
return ms.Unmarshal(marshaled, acc)
|
||||
}
|
||||
|
||||
func NewTCC() (StatMetric, error) {
|
||||
return &StatTCC{Events: make(map[string]float64)}, nil
|
||||
func NewTCC(minItems int) (StatMetric, error) {
|
||||
return &StatTCC{Events: make(map[string]float64), MinItems: minItems}, nil
|
||||
}
|
||||
|
||||
// TCC implements TotalCallCost metric
|
||||
type StatTCC struct {
|
||||
Sum float64
|
||||
Count float64
|
||||
Events map[string]float64 // map[EventTenantID]Cost
|
||||
val *float64 // cached TCC value
|
||||
Sum float64
|
||||
Count float64
|
||||
Events map[string]float64 // map[EventTenantID]Cost
|
||||
MinItems int
|
||||
val *float64 // cached TCC value
|
||||
}
|
||||
|
||||
// getValue returns tcd.val
|
||||
func (tcc *StatTCC) getValue() float64 {
|
||||
if tcc.val == nil {
|
||||
if tcc.Count == 0 {
|
||||
tcc.val = utils.Float64Pointer(float64(STATS_NA))
|
||||
if (tcc.MinItems > 0 && len(tcc.Events) < tcc.MinItems) || (tcc.Count == 0) {
|
||||
tcc.val = utils.Float64Pointer(STATS_NA)
|
||||
} else {
|
||||
tcc.val = utils.Float64Pointer(utils.Round(tcc.Sum,
|
||||
config.CgrConfig().RoundingDecimals, utils.ROUNDING_MIDDLE))
|
||||
@@ -412,11 +429,13 @@ func (tcc *StatTCC) getValue() float64 {
|
||||
return *tcc.val
|
||||
}
|
||||
|
||||
func (tcc *StatTCC) GetStringValue(fmtOpts string) (val string) {
|
||||
if tcc.Count == 0 {
|
||||
return utils.NOT_AVAILABLE
|
||||
func (tcc *StatTCC) GetStringValue(fmtOpts string) (valStr string) {
|
||||
if val := tcc.getValue(); val == STATS_NA {
|
||||
valStr = utils.NOT_AVAILABLE
|
||||
} else {
|
||||
valStr = strconv.FormatFloat(tcc.getValue(), 'f', -1, 64)
|
||||
}
|
||||
return strconv.FormatFloat(tcc.getValue(), 'f', -1, 64)
|
||||
return
|
||||
}
|
||||
|
||||
func (tcc *StatTCC) GetValue() (v interface{}) {
|
||||
@@ -468,22 +487,23 @@ func (tcc *StatTCC) LoadMarshaled(ms Marshaler, marshaled []byte) (err error) {
|
||||
return ms.Unmarshal(marshaled, tcc)
|
||||
}
|
||||
|
||||
func NewPDD() (StatMetric, error) {
|
||||
return &StatPDD{Events: make(map[string]time.Duration)}, nil
|
||||
func NewPDD(minItems int) (StatMetric, error) {
|
||||
return &StatPDD{Events: make(map[string]time.Duration), MinItems: minItems}, nil
|
||||
}
|
||||
|
||||
// PDD implements Post Dial Delay (average) metric
|
||||
type StatPDD struct {
|
||||
Sum time.Duration
|
||||
Count int64
|
||||
Events map[string]time.Duration // map[EventTenantID]Duration
|
||||
val *time.Duration // cached PDD value
|
||||
Sum time.Duration
|
||||
Count int64
|
||||
Events map[string]time.Duration // map[EventTenantID]Duration
|
||||
MinItems int
|
||||
val *time.Duration // cached PDD value
|
||||
}
|
||||
|
||||
// getValue returns pdd.val
|
||||
func (pdd *StatPDD) getValue() time.Duration {
|
||||
if pdd.val == nil {
|
||||
if pdd.Count == 0 {
|
||||
if (pdd.MinItems > 0 && len(pdd.Events) < pdd.MinItems) || (pdd.Count == 0) {
|
||||
pdd.val = utils.DurationPointer(time.Duration((-1) * time.Nanosecond))
|
||||
} else {
|
||||
pdd.val = utils.DurationPointer(time.Duration(pdd.Sum.Nanoseconds() / pdd.Count))
|
||||
@@ -492,11 +512,13 @@ func (pdd *StatPDD) getValue() time.Duration {
|
||||
return *pdd.val
|
||||
}
|
||||
|
||||
func (pdd *StatPDD) GetStringValue(fmtOpts string) (val string) {
|
||||
if pdd.Count == 0 {
|
||||
return utils.NOT_AVAILABLE
|
||||
func (pdd *StatPDD) GetStringValue(fmtOpts string) (valStr string) {
|
||||
if val := pdd.getValue(); val == time.Duration((-1)*time.Nanosecond) {
|
||||
valStr = utils.NOT_AVAILABLE
|
||||
} else {
|
||||
valStr = fmt.Sprintf("%+v", pdd.getValue())
|
||||
}
|
||||
return fmt.Sprintf("%+v", pdd.getValue())
|
||||
return
|
||||
}
|
||||
|
||||
func (pdd *StatPDD) GetValue() (v interface{}) {
|
||||
@@ -504,10 +526,12 @@ func (pdd *StatPDD) GetValue() (v interface{}) {
|
||||
}
|
||||
|
||||
func (pdd *StatPDD) GetFloat64Value() (v float64) {
|
||||
if pdd.Count == 0 {
|
||||
return -1.0
|
||||
if val := pdd.getValue(); val == time.Duration((-1)*time.Nanosecond) {
|
||||
v = -1.0
|
||||
} else {
|
||||
v = pdd.getValue().Seconds()
|
||||
}
|
||||
return pdd.getValue().Seconds()
|
||||
return
|
||||
}
|
||||
|
||||
func (pdd *StatPDD) AddEvent(ev *StatEvent) (err error) {
|
||||
@@ -551,21 +575,24 @@ func (pdd *StatPDD) LoadMarshaled(ms Marshaler, marshaled []byte) (err error) {
|
||||
return ms.Unmarshal(marshaled, pdd)
|
||||
}
|
||||
|
||||
func NewDCC() (StatMetric, error) {
|
||||
return &StatDDC{Destinations: make(map[string]utils.StringMap), EventDestinations: make(map[string]string)}, nil
|
||||
func NewDCC(minItems int) (StatMetric, error) {
|
||||
return &StatDDC{Destinations: make(map[string]utils.StringMap), Events: make(map[string]string), MinItems: minItems}, nil
|
||||
}
|
||||
|
||||
// DDC implements Destination Distinct Count metric
|
||||
type StatDDC struct {
|
||||
Destinations map[string]utils.StringMap
|
||||
EventDestinations map[string]string // map[EventTenantID]Destination
|
||||
Destinations map[string]utils.StringMap
|
||||
Events map[string]string // map[EventTenantID]Destination
|
||||
MinItems int
|
||||
}
|
||||
|
||||
func (ddc *StatDDC) GetStringValue(fmtOpts string) (val string) {
|
||||
if len(ddc.Destinations) == 0 {
|
||||
return utils.NOT_AVAILABLE
|
||||
func (ddc *StatDDC) GetStringValue(fmtOpts string) (valStr string) {
|
||||
if val := len(ddc.Destinations); (val == 0) || (ddc.MinItems > 0 && len(ddc.Events) < ddc.MinItems) {
|
||||
valStr = utils.NOT_AVAILABLE
|
||||
} else {
|
||||
valStr = fmt.Sprintf("%+v", len(ddc.Destinations))
|
||||
}
|
||||
return fmt.Sprintf("%+v", len(ddc.Destinations))
|
||||
return
|
||||
}
|
||||
|
||||
func (ddc *StatDDC) GetValue() (v interface{}) {
|
||||
@@ -573,10 +600,12 @@ func (ddc *StatDDC) GetValue() (v interface{}) {
|
||||
}
|
||||
|
||||
func (ddc *StatDDC) GetFloat64Value() (v float64) {
|
||||
if len(ddc.Destinations) == 0 {
|
||||
return -1.0
|
||||
if val := len(ddc.Destinations); (val == 0) || (ddc.MinItems > 0 && len(ddc.Events) < ddc.MinItems) {
|
||||
v = -1.0
|
||||
} else {
|
||||
v = float64(len(ddc.Destinations))
|
||||
}
|
||||
return float64(len(ddc.Destinations))
|
||||
return
|
||||
}
|
||||
|
||||
func (ddc *StatDDC) AddEvent(ev *StatEvent) (err error) {
|
||||
@@ -588,16 +617,16 @@ func (ddc *StatDDC) AddEvent(ev *StatEvent) (err error) {
|
||||
ddc.Destinations[dest] = make(map[string]bool)
|
||||
}
|
||||
ddc.Destinations[dest][ev.TenantID()] = true
|
||||
ddc.EventDestinations[ev.TenantID()] = dest
|
||||
ddc.Events[ev.TenantID()] = dest
|
||||
return
|
||||
}
|
||||
|
||||
func (ddc *StatDDC) RemEvent(evTenantID string) (err error) {
|
||||
destination, has := ddc.EventDestinations[evTenantID]
|
||||
destination, has := ddc.Events[evTenantID]
|
||||
if !has {
|
||||
return utils.ErrNotFound
|
||||
}
|
||||
delete(ddc.EventDestinations, evTenantID)
|
||||
delete(ddc.Events, evTenantID)
|
||||
if len(ddc.Destinations[destination]) == 1 {
|
||||
delete(ddc.Destinations, destination)
|
||||
return
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
)
|
||||
|
||||
func TestASRGetStringValue(t *testing.T) {
|
||||
asr, _ := NewASR()
|
||||
asr, _ := NewASR(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC)}}
|
||||
@@ -32,12 +32,15 @@ func TestASRGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong asr value: %s", strVal)
|
||||
}
|
||||
asr.AddEvent(ev)
|
||||
if strVal := asr.GetStringValue(""); strVal != "100%" {
|
||||
if strVal := asr.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong asr value: %s", strVal)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
ev3 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_3"}
|
||||
asr.AddEvent(ev2)
|
||||
if strVal := asr.GetStringValue(""); strVal != "50%" {
|
||||
t.Errorf("wrong asr value: %s", strVal)
|
||||
}
|
||||
asr.AddEvent(ev3)
|
||||
if strVal := asr.GetStringValue(""); strVal != "33.33333%" {
|
||||
t.Errorf("wrong asr value: %s", strVal)
|
||||
@@ -70,12 +73,12 @@ func TestASRGetStringValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestASRGetValue(t *testing.T) {
|
||||
asr, _ := NewASR()
|
||||
asr, _ := NewASR(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC)}}
|
||||
asr.AddEvent(ev)
|
||||
if v := asr.GetValue(); v != 100.0 {
|
||||
if v := asr.GetValue(); v != -1.0 {
|
||||
t.Errorf("wrong asr value: %f", v)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
@@ -106,7 +109,7 @@ func TestASRGetValue(t *testing.T) {
|
||||
t.Errorf("wrong asr value: %f", v)
|
||||
}
|
||||
asr.RemEvent(ev4.TenantID())
|
||||
if v := asr.GetValue(); v != 100.0 {
|
||||
if v := asr.GetValue(); v != -1.0 {
|
||||
t.Errorf("wrong asr value: %f", v)
|
||||
}
|
||||
asr.RemEvent(ev5.TenantID())
|
||||
@@ -116,7 +119,7 @@ func TestASRGetValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestACDGetStringValue(t *testing.T) {
|
||||
acd, _ := NewACD()
|
||||
acd, _ := NewACD(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
utils.USAGE: time.Duration(10 * time.Second),
|
||||
@@ -126,18 +129,17 @@ func TestACDGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong acd value: %s", strVal)
|
||||
}
|
||||
acd.AddEvent(ev)
|
||||
if strVal := acd.GetStringValue(""); strVal != "10s" {
|
||||
if strVal := acd.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong acd value: %s", strVal)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
ev3 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_3"}
|
||||
acd.AddEvent(ev2)
|
||||
acd.AddEvent(ev3)
|
||||
if strVal := acd.GetStringValue(""); strVal != "10s" {
|
||||
if strVal := acd.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong acd value: %s", strVal)
|
||||
}
|
||||
acd.RemEvent(ev3.TenantID())
|
||||
if strVal := acd.GetStringValue(""); strVal != "10s" {
|
||||
if strVal := acd.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong acd value: %s", strVal)
|
||||
}
|
||||
acd.RemEvent(ev.TenantID())
|
||||
@@ -157,7 +159,7 @@ func TestACDGetStringValue(t *testing.T) {
|
||||
},
|
||||
}
|
||||
acd.AddEvent(ev4)
|
||||
if strVal := acd.GetStringValue(""); strVal != "1m0s" {
|
||||
if strVal := acd.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong acd value: %s", strVal)
|
||||
}
|
||||
acd.AddEvent(ev5)
|
||||
@@ -177,18 +179,18 @@ func TestACDGetStringValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestACDGetFloat64Value(t *testing.T) {
|
||||
acd, _ := NewACD()
|
||||
acd, _ := NewACD(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
"Usage": time.Duration(10 * time.Second)}}
|
||||
acd.AddEvent(ev)
|
||||
if v := acd.GetFloat64Value(); v != 10.0 {
|
||||
if v := acd.GetFloat64Value(); v != -1.0 {
|
||||
t.Errorf("wrong acd value: %v", v)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
acd.AddEvent(ev2)
|
||||
if v := acd.GetFloat64Value(); v != 10.0 {
|
||||
if v := acd.GetFloat64Value(); v != -1.0 {
|
||||
t.Errorf("wrong acd value: %v", v)
|
||||
}
|
||||
ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4",
|
||||
@@ -220,7 +222,7 @@ func TestACDGetFloat64Value(t *testing.T) {
|
||||
t.Errorf("wrong acd value: %v", strVal)
|
||||
}
|
||||
acd.RemEvent(ev.TenantID())
|
||||
if strVal := acd.GetFloat64Value(); strVal != 90.0 {
|
||||
if strVal := acd.GetFloat64Value(); strVal != -1.0 {
|
||||
t.Errorf("wrong acd value: %v", strVal)
|
||||
}
|
||||
acd.RemEvent(ev5.TenantID())
|
||||
@@ -230,13 +232,13 @@ func TestACDGetFloat64Value(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestACDGetValue(t *testing.T) {
|
||||
acd, _ := NewACD()
|
||||
acd, _ := NewACD(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
"Usage": time.Duration(10 * time.Second)}}
|
||||
acd.AddEvent(ev)
|
||||
if v := acd.GetValue(); v != time.Duration(10*time.Second) {
|
||||
if v := acd.GetValue(); v != time.Duration((-1)*time.Nanosecond) {
|
||||
t.Errorf("wrong acd value: %+v", v)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2",
|
||||
@@ -250,7 +252,7 @@ func TestACDGetValue(t *testing.T) {
|
||||
t.Errorf("wrong acd value: %+v", v)
|
||||
}
|
||||
acd.RemEvent(ev.TenantID())
|
||||
if v := acd.GetValue(); v != time.Duration(8*time.Second) {
|
||||
if v := acd.GetValue(); v != time.Duration((-1)*time.Nanosecond) {
|
||||
t.Errorf("wrong acd value: %+v", v)
|
||||
}
|
||||
acd.RemEvent(ev2.TenantID())
|
||||
@@ -286,7 +288,7 @@ func TestACDGetValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTCDGetStringValue(t *testing.T) {
|
||||
tcd, _ := NewTCD()
|
||||
tcd, _ := NewTCD(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"Usage": time.Duration(10 * time.Second),
|
||||
@@ -296,7 +298,7 @@ func TestTCDGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong tcd value: %s", strVal)
|
||||
}
|
||||
tcd.AddEvent(ev)
|
||||
if strVal := tcd.GetStringValue(""); strVal != "10s" {
|
||||
if strVal := tcd.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong tcd value: %s", strVal)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2",
|
||||
@@ -311,7 +313,7 @@ func TestTCDGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong tcd value: %s", strVal)
|
||||
}
|
||||
tcd.RemEvent(ev2.TenantID())
|
||||
if strVal := tcd.GetStringValue(""); strVal != "10s" {
|
||||
if strVal := tcd.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong tcd value: %s", strVal)
|
||||
}
|
||||
tcd.RemEvent(ev.TenantID())
|
||||
@@ -336,7 +338,7 @@ func TestTCDGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong tcd value: %s", strVal)
|
||||
}
|
||||
tcd.RemEvent(ev4.TenantID())
|
||||
if strVal := tcd.GetStringValue(""); strVal != "1m30s" {
|
||||
if strVal := tcd.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong tcd value: %s", strVal)
|
||||
}
|
||||
tcd.RemEvent(ev5.TenantID())
|
||||
@@ -347,18 +349,18 @@ func TestTCDGetStringValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTCDGetFloat64Value(t *testing.T) {
|
||||
tcd, _ := NewTCD()
|
||||
tcd, _ := NewTCD(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
"Usage": time.Duration(10 * time.Second)}}
|
||||
tcd.AddEvent(ev)
|
||||
if v := tcd.GetFloat64Value(); v != 10.0 {
|
||||
if v := tcd.GetFloat64Value(); v != -1.0 {
|
||||
t.Errorf("wrong tcd value: %f", v)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
tcd.AddEvent(ev2)
|
||||
if v := tcd.GetFloat64Value(); v != 10.0 {
|
||||
if v := tcd.GetFloat64Value(); v != -1.0 {
|
||||
t.Errorf("wrong tcd value: %f", v)
|
||||
}
|
||||
ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4",
|
||||
@@ -390,7 +392,7 @@ func TestTCDGetFloat64Value(t *testing.T) {
|
||||
t.Errorf("wrong tcd value: %f", strVal)
|
||||
}
|
||||
tcd.RemEvent(ev.TenantID())
|
||||
if strVal := tcd.GetFloat64Value(); strVal != 90.0 {
|
||||
if strVal := tcd.GetFloat64Value(); strVal != -1.0 {
|
||||
t.Errorf("wrong tcd value: %f", strVal)
|
||||
}
|
||||
tcd.RemEvent(ev5.TenantID())
|
||||
@@ -400,13 +402,13 @@ func TestTCDGetFloat64Value(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTCDGetValue(t *testing.T) {
|
||||
tcd, _ := NewTCD()
|
||||
tcd, _ := NewTCD(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
"Usage": time.Duration(10 * time.Second)}}
|
||||
tcd.AddEvent(ev)
|
||||
if v := tcd.GetValue(); v != time.Duration(10*time.Second) {
|
||||
if v := tcd.GetValue(); v != time.Duration((-1)*time.Nanosecond) {
|
||||
t.Errorf("wrong tcd value: %+v", v)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2",
|
||||
@@ -420,7 +422,7 @@ func TestTCDGetValue(t *testing.T) {
|
||||
t.Errorf("wrong tcd value: %+v", v)
|
||||
}
|
||||
tcd.RemEvent(ev.TenantID())
|
||||
if v := tcd.GetValue(); v != time.Duration(5*time.Second) {
|
||||
if v := tcd.GetValue(); v != time.Duration((-1)*time.Nanosecond) {
|
||||
t.Errorf("wrong tcd value: %+v", v)
|
||||
}
|
||||
tcd.RemEvent(ev2.TenantID())
|
||||
@@ -456,7 +458,7 @@ func TestTCDGetValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestACCGetStringValue(t *testing.T) {
|
||||
acc, _ := NewACC()
|
||||
acc, _ := NewACC(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
@@ -465,18 +467,21 @@ func TestACCGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong acc value: %s", strVal)
|
||||
}
|
||||
acc.AddEvent(ev)
|
||||
if strVal := acc.GetStringValue(""); strVal != "12.3" {
|
||||
if strVal := acc.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong acc value: %s", strVal)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
ev3 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_3"}
|
||||
ev3 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_3",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
"Cost": 12.3}}
|
||||
acc.AddEvent(ev2)
|
||||
acc.AddEvent(ev3)
|
||||
if strVal := acc.GetStringValue(""); strVal != "12.3" {
|
||||
t.Errorf("wrong acc value: %s", strVal)
|
||||
}
|
||||
acc.RemEvent(ev3.TenantID())
|
||||
if strVal := acc.GetStringValue(""); strVal != "12.3" {
|
||||
if strVal := acc.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong acc value: %s", strVal)
|
||||
}
|
||||
ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4",
|
||||
@@ -505,7 +510,7 @@ func TestACCGetStringValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestACCGetValue(t *testing.T) {
|
||||
acc, _ := NewACC()
|
||||
acc, _ := NewACC(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
@@ -514,18 +519,18 @@ func TestACCGetValue(t *testing.T) {
|
||||
t.Errorf("wrong acc value: %v", strVal)
|
||||
}
|
||||
acc.AddEvent(ev)
|
||||
if strVal := acc.GetValue(); strVal != 12.3 {
|
||||
if strVal := acc.GetValue(); strVal != -1.0 {
|
||||
t.Errorf("wrong acc value: %v", strVal)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
ev3 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_3"}
|
||||
acc.AddEvent(ev2)
|
||||
acc.AddEvent(ev3)
|
||||
if strVal := acc.GetValue(); strVal != 12.3 {
|
||||
if strVal := acc.GetValue(); strVal != -1.0 {
|
||||
t.Errorf("wrong acc value: %v", strVal)
|
||||
}
|
||||
acc.RemEvent(ev3.TenantID())
|
||||
if strVal := acc.GetValue(); strVal != 12.3 {
|
||||
if strVal := acc.GetValue(); strVal != -1.0 {
|
||||
t.Errorf("wrong acc value: %v", strVal)
|
||||
}
|
||||
ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4",
|
||||
@@ -554,7 +559,7 @@ func TestACCGetValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTCCGetStringValue(t *testing.T) {
|
||||
tcc, _ := NewTCC()
|
||||
tcc, _ := NewTCC(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
@@ -563,7 +568,7 @@ func TestTCCGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong tcc value: %s", strVal)
|
||||
}
|
||||
tcc.AddEvent(ev)
|
||||
if strVal := tcc.GetStringValue(""); strVal != "12.3" {
|
||||
if strVal := tcc.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong tcc value: %s", strVal)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
@@ -577,7 +582,7 @@ func TestTCCGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong tcc value: %s", strVal)
|
||||
}
|
||||
tcc.RemEvent(ev3.TenantID())
|
||||
if strVal := tcc.GetStringValue(""); strVal != "12.3" {
|
||||
if strVal := tcc.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong tcc value: %s", strVal)
|
||||
}
|
||||
ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4",
|
||||
@@ -606,7 +611,7 @@ func TestTCCGetStringValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTCCGetValue(t *testing.T) {
|
||||
tcc, _ := NewTCC()
|
||||
tcc, _ := NewTCC(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
@@ -615,7 +620,7 @@ func TestTCCGetValue(t *testing.T) {
|
||||
t.Errorf("wrong tcc value: %v", strVal)
|
||||
}
|
||||
tcc.AddEvent(ev)
|
||||
if strVal := tcc.GetValue(); strVal != 12.3 {
|
||||
if strVal := tcc.GetValue(); strVal != -1.0 {
|
||||
t.Errorf("wrong tcc value: %v", strVal)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
@@ -629,7 +634,7 @@ func TestTCCGetValue(t *testing.T) {
|
||||
t.Errorf("wrong tcc value: %v", strVal)
|
||||
}
|
||||
tcc.RemEvent(ev3.TenantID())
|
||||
if strVal := tcc.GetValue(); strVal != 12.3 {
|
||||
if strVal := tcc.GetValue(); strVal != -1.0 {
|
||||
t.Errorf("wrong tcc value: %v", strVal)
|
||||
}
|
||||
ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4",
|
||||
@@ -658,7 +663,7 @@ func TestTCCGetValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPDDGetStringValue(t *testing.T) {
|
||||
pdd, _ := NewPDD()
|
||||
pdd, _ := NewPDD(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
utils.USAGE: time.Duration(10 * time.Second),
|
||||
@@ -669,7 +674,7 @@ func TestPDDGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong pdd value: %s", strVal)
|
||||
}
|
||||
pdd.AddEvent(ev)
|
||||
if strVal := pdd.GetStringValue(""); strVal != "5s" {
|
||||
if strVal := pdd.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong pdd value: %s", strVal)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
@@ -684,7 +689,7 @@ func TestPDDGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong pdd value: %s", strVal)
|
||||
}
|
||||
pdd.RemEvent(ev.TenantID())
|
||||
if strVal := pdd.GetStringValue(""); strVal != "0s" {
|
||||
if strVal := pdd.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong pdd value: %s", strVal)
|
||||
}
|
||||
ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4",
|
||||
@@ -720,14 +725,14 @@ func TestPDDGetStringValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPDDGetFloat64Value(t *testing.T) {
|
||||
pdd, _ := NewPDD()
|
||||
pdd, _ := NewPDD(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
"Usage": time.Duration(10 * time.Second),
|
||||
utils.PDD: time.Duration(5 * time.Second)}}
|
||||
pdd.AddEvent(ev)
|
||||
if v := pdd.GetFloat64Value(); v != 5.0 {
|
||||
if v := pdd.GetFloat64Value(); v != -1.0 {
|
||||
t.Errorf("wrong pdd value: %v", v)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
@@ -765,7 +770,7 @@ func TestPDDGetFloat64Value(t *testing.T) {
|
||||
t.Errorf("wrong pdd value: %v", strVal)
|
||||
}
|
||||
pdd.RemEvent(ev.TenantID())
|
||||
if strVal := pdd.GetFloat64Value(); strVal != 0 {
|
||||
if strVal := pdd.GetFloat64Value(); strVal != -1.0 {
|
||||
t.Errorf("wrong pdd value: %v", strVal)
|
||||
}
|
||||
pdd.RemEvent(ev5.TenantID())
|
||||
@@ -775,14 +780,14 @@ func TestPDDGetFloat64Value(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPDDGetValue(t *testing.T) {
|
||||
pdd, _ := NewPDD()
|
||||
pdd, _ := NewPDD(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
"Usage": time.Duration(10 * time.Second),
|
||||
utils.PDD: time.Duration(9 * time.Second)}}
|
||||
pdd.AddEvent(ev)
|
||||
if v := pdd.GetValue(); v != time.Duration(9*time.Second) {
|
||||
if v := pdd.GetValue(); v != time.Duration((-1)*time.Nanosecond) {
|
||||
t.Errorf("wrong pdd value: %+v", v)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2",
|
||||
@@ -801,7 +806,7 @@ func TestPDDGetValue(t *testing.T) {
|
||||
t.Errorf("wrong pdd value: %+v", v)
|
||||
}
|
||||
pdd.RemEvent(ev2.TenantID())
|
||||
if v := pdd.GetValue(); v != time.Duration(0*time.Second) {
|
||||
if v := pdd.GetValue(); v != time.Duration((-1)*time.Nanosecond) {
|
||||
t.Errorf("wrong pdd value: %+v", v)
|
||||
}
|
||||
ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4",
|
||||
@@ -824,7 +829,7 @@ func TestPDDGetValue(t *testing.T) {
|
||||
}
|
||||
pdd.RemEvent(ev5.TenantID())
|
||||
pdd.RemEvent(ev4.TenantID())
|
||||
if v := pdd.GetValue(); v != time.Duration(0*time.Second) {
|
||||
if v := pdd.GetValue(); v != time.Duration((-1)*time.Nanosecond) {
|
||||
t.Errorf("wrong pdd value: %+v", v)
|
||||
}
|
||||
pdd.RemEvent(ev3.TenantID())
|
||||
@@ -834,7 +839,7 @@ func TestPDDGetValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDDCGetStringValue(t *testing.T) {
|
||||
ddc, _ := NewDCC()
|
||||
ddc, _ := NewDCC(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
@@ -844,7 +849,7 @@ func TestDDCGetStringValue(t *testing.T) {
|
||||
}
|
||||
|
||||
ddc.AddEvent(ev)
|
||||
if strVal := ddc.GetStringValue(""); strVal != "1" {
|
||||
if strVal := ddc.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong ddc value: %s", strVal)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2",
|
||||
@@ -866,7 +871,7 @@ func TestDDCGetStringValue(t *testing.T) {
|
||||
t.Errorf("wrong ddc value: %s", strVal)
|
||||
}
|
||||
ddc.RemEvent(ev2.TenantID())
|
||||
if strVal := ddc.GetStringValue(""); strVal != "1" {
|
||||
if strVal := ddc.GetStringValue(""); strVal != utils.NOT_AVAILABLE {
|
||||
t.Errorf("wrong ddc value: %s", strVal)
|
||||
}
|
||||
ddc.RemEvent(ev3.TenantID())
|
||||
@@ -876,7 +881,7 @@ func TestDDCGetStringValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDDCGetFloat64Value(t *testing.T) {
|
||||
ddc, _ := NewDCC()
|
||||
ddc, _ := NewDCC(2)
|
||||
ev := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_1",
|
||||
Fields: map[string]interface{}{
|
||||
"AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
@@ -884,12 +889,12 @@ func TestDDCGetFloat64Value(t *testing.T) {
|
||||
utils.PDD: time.Duration(5 * time.Second),
|
||||
utils.DESTINATION: "1002"}}
|
||||
ddc.AddEvent(ev)
|
||||
if v := ddc.GetFloat64Value(); v != 1 {
|
||||
if v := ddc.GetFloat64Value(); v != -1.0 {
|
||||
t.Errorf("wrong ddc value: %v", v)
|
||||
}
|
||||
ev2 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_2"}
|
||||
ddc.AddEvent(ev2)
|
||||
if v := ddc.GetFloat64Value(); v != 1 {
|
||||
if v := ddc.GetFloat64Value(); v != -1.0 {
|
||||
t.Errorf("wrong ddc value: %v", v)
|
||||
}
|
||||
ev4 := &StatEvent{Tenant: "cgrates.org", ID: "EVENT_4",
|
||||
@@ -924,7 +929,7 @@ func TestDDCGetFloat64Value(t *testing.T) {
|
||||
t.Errorf("wrong ddc value: %v", strVal)
|
||||
}
|
||||
ddc.RemEvent(ev.TenantID())
|
||||
if strVal := ddc.GetFloat64Value(); strVal != 1 {
|
||||
if strVal := ddc.GetFloat64Value(); strVal != -1.0 {
|
||||
t.Errorf("wrong ddc value: %v", strVal)
|
||||
}
|
||||
ddc.RemEvent(ev5.TenantID())
|
||||
|
||||
@@ -37,7 +37,7 @@ const ACC = "ACC"
|
||||
const TCC = "TCC"
|
||||
const PDD = "PDD"
|
||||
const DDC = "DDC"
|
||||
const STATS_NA = -1
|
||||
const STATS_NA = -1.0
|
||||
|
||||
func CreateMetric(metric string) Metric {
|
||||
switch metric {
|
||||
|
||||
@@ -607,7 +607,7 @@ func (self *SQLStorage) SetTPStats(sts []*utils.TPStats) error {
|
||||
tx := self.db.Begin()
|
||||
for _, stq := range sts {
|
||||
// Remove previous
|
||||
if err := tx.Where(&TpStats{Tpid: stq.TPid, Tag: stq.ID}).Delete(TpStats{}).Error; err != nil {
|
||||
if err := tx.Where(&TpStats{Tpid: stq.TPid, ID: stq.ID}).Delete(TpStats{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
@@ -629,7 +629,7 @@ func (self *SQLStorage) SetTPThreshold(ths []*utils.TPThreshold) error {
|
||||
tx := self.db.Begin()
|
||||
for _, th := range ths {
|
||||
// Remove previous
|
||||
if err := tx.Where(&TpThreshold{Tpid: th.TPid, Tag: th.ID}).Delete(TpThreshold{}).Error; err != nil {
|
||||
if err := tx.Where(&TpThreshold{Tpid: th.TPid, ID: th.ID}).Delete(TpThreshold{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
@@ -1578,7 +1578,7 @@ func (self *SQLStorage) GetTPStats(tpid, id string) ([]*utils.TPStats, error) {
|
||||
var sts TpStatsS
|
||||
q := self.db.Where("tpid = ?", tpid)
|
||||
if len(id) != 0 {
|
||||
q = q.Where("tag = ?", id)
|
||||
q = q.Where("id = ?", id)
|
||||
}
|
||||
if err := q.Find(&sts).Error; err != nil {
|
||||
return nil, err
|
||||
@@ -1594,7 +1594,7 @@ func (self *SQLStorage) GetTPThreshold(tpid, id string) ([]*utils.TPThreshold, e
|
||||
var ths TpThresholdS
|
||||
q := self.db.Where("tpid = ?", tpid)
|
||||
if len(id) != 0 {
|
||||
q = q.Where("tag = ?", id)
|
||||
q = q.Where("id = ?", id)
|
||||
}
|
||||
if err := q.Find(&ths).Error; err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1578,6 +1578,7 @@ func testStorDBitCRUDTpStats(t *testing.T) {
|
||||
Metrics: []string{"*asr", "*acd", "*acc"},
|
||||
Thresholds: []string{"THRESH1", "THRESH2"},
|
||||
Weight: 20.0,
|
||||
MinItems: 1,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -2028,7 +2028,7 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err
|
||||
sq := &StatQueue{Tenant: sqTntID.Tenant, ID: sqTntID.ID,
|
||||
SQMetrics: make(map[string]StatMetric)}
|
||||
for _, metricID := range tpr.sqProfiles[sqTntID.Tenant][sqTntID.ID].Metrics {
|
||||
if metric, err := NewStatMetric(metricID); err != nil {
|
||||
if metric, err := NewStatMetric(metricID, tpr.sqProfiles[sqTntID.Tenant][sqTntID.ID].MinItems); err != nil {
|
||||
return err
|
||||
} else {
|
||||
sq.SQMetrics[metricID] = metric
|
||||
|
||||
@@ -1351,6 +1351,7 @@ type TPStats struct {
|
||||
Blocker bool // blocker flag to stop processing on filters matched
|
||||
Stored bool
|
||||
Weight float64
|
||||
MinItems int
|
||||
Thresholds []string
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user