diff --git a/engine/statsqueue.go b/engine/statsqueue.go index 3e372dc13..a5acbfa02 100644 --- a/engine/statsqueue.go +++ b/engine/statsqueue.go @@ -18,6 +18,7 @@ along with this program. If not, see package engine import ( + "errors" "time" "github.com/cgrates/cgrates/utils" @@ -37,16 +38,6 @@ type SQStoredMetrics struct { SQMetrics map[string][]byte } -// StatsEvent is an event received by StatService -type StatsEvent map[string]interface{} - -func (se StatsEvent) ID() (id string) { - if sID, has := se[utils.ID]; has { - id = sID.(string) - } - return -} - // StatsQueue represents the configuration of a StatsInstance in StatS type StatsQueue struct { ID string // QueueID @@ -59,3 +50,29 @@ type StatsQueue struct { Thresholds []string // list of thresholds to be checked after changes Weight float64 } + +// StatsEvent is an event received by StatService +type StatsEvent map[string]interface{} + +func (se StatsEvent) ID() (id string) { + if sID, has := se[utils.ID]; has { + id = sID.(string) + } + return +} + +// AnswerTime returns the AnswerTime of StatsEvent +func (se StatsEvent) AnswerTime(timezone string) (at time.Time, err error) { + atIf, has := se[utils.ANSWER_TIME] + if !has { + return at, utils.ErrNotFound + } + if at, canCast := atIf.(time.Time); canCast { + return at, nil + } + atStr, canCast := atIf.(string) + if !canCast { + return at, errors.New("cannot cast to string") + } + return utils.ParseTimeDetectLayout(atStr, timezone) +} diff --git a/stats/acd.go b/stats/acd.go index 5abf9576b..125050c10 100644 --- a/stats/acd.go +++ b/stats/acd.go @@ -19,6 +19,8 @@ along with this program. If not, see package stats import ( + "time" + "github.com/cgrates/cgrates/engine" ) @@ -27,7 +29,10 @@ func NewACD() (StatsMetric, error) { } // ACD implements AverageCallDuration metric -type ACD struct{} +type ACD struct { + Sum time.Duration + Count int +} func (acd *ACD) GetStringValue(fmtOpts string) (val string) { return diff --git a/stats/asr.go b/stats/asr.go index 16c815d1a..dc4964115 100644 --- a/stats/asr.go +++ b/stats/asr.go @@ -19,7 +19,11 @@ along with this program. If not, see package stats import ( + "fmt" + + "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" ) func NewASR() (StatsMetric, error) { @@ -28,26 +32,43 @@ func NewASR() (StatsMetric, error) { // ASR implements AverageSuccessRatio metric type ASR struct { - answered int - count int + Answered float64 + Count float64 } -func (asr *ASR) GetStringValue(fmtOpts string) (val string) { - return +func (asr *ASR) GetStringValue(fmtOpts string) (valStr string) { + if asr.Count == 0 { + return utils.NOT_AVAILABLE + } + val := utils.Round((asr.Answered / asr.Count * 100), + config.CgrConfig().RoundingDecimals, utils.ROUNDING_MIDDLE) + return fmt.Sprintf("%v%%", val) } func (asr *ASR) AddEvent(ev engine.StatsEvent) (err error) { + if at, err := ev.AnswerTime(config.CgrConfig().DefaultTimezone); err != nil { + return err + } else if !at.IsZero() { + asr.Answered += 1 + } + asr.Count += 1 return } func (asr *ASR) RemEvent(ev engine.StatsEvent) (err error) { + if at, err := ev.AnswerTime(config.CgrConfig().DefaultTimezone); err != nil { + return err + } else if !at.IsZero() { + asr.Answered -= 1 + } + asr.Count -= 1 return } func (asr *ASR) GetMarshaled(ms engine.Marshaler) (vals []byte, err error) { - return + return ms.Marshal(asr) } func (asr *ASR) SetFromMarshaled(vals []byte, ms engine.Marshaler) (err error) { - return + return ms.Unmarshal(vals, asr) } diff --git a/stats/asr_test.go b/stats/asr_test.go new file mode 100644 index 000000000..7064513c0 --- /dev/null +++ b/stats/asr_test.go @@ -0,0 +1,36 @@ +/* +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 stats + +import ( + "testing" + "time" + + "github.com/cgrates/cgrates/engine" +) + +func TestASRAddRemEvent(t *testing.T) { + asr, _ := NewASR() + ev := engine.StatsEvent{ + "AnswerTime": time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + } + asr.AddEvent(ev) + if strVal := asr.GetStringValue(""); strVal != "100%" { + t.Errorf("wrong asr value: %s", strVal) + } +} diff --git a/stats/metric.go b/stats/metric.go index 014462035..cd8987045 100644 --- a/stats/metric.go +++ b/stats/metric.go @@ -26,6 +26,7 @@ import ( ) // NewStatsMetrics instantiates the StatsMetrics +// cfg serves as general purpose container to pass config options to metric func NewStatsMetric(metricID string) (sm StatsMetric, err error) { metrics := map[string]func() (StatsMetric, error){ utils.MetaASR: NewASR,