From 2fef2248e15e0438b9abe9bc2dc9c0df41e1942d Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 1 Jul 2014 15:16:11 +0300 Subject: [PATCH] started cdr stats --- cdrstats/metrics.go | 60 ++++++++++++++ cdrstats/stats.go | 166 +++++++++++++++++++++++++++++++++++++++ cdrstats/stats_test.go | 19 +++++ config/cdrstatsconfig.go | 1 - utils/storedcdr.go | 2 +- 5 files changed, 246 insertions(+), 2 deletions(-) create mode 100644 cdrstats/metrics.go create mode 100644 cdrstats/stats.go create mode 100644 cdrstats/stats_test.go diff --git a/cdrstats/metrics.go b/cdrstats/metrics.go new file mode 100644 index 000000000..2a27268cf --- /dev/null +++ b/cdrstats/metrics.go @@ -0,0 +1,60 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +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 cdrstats + +type Metric interface { + AddCDR(*QCDR) + RemoveCDR(*QCDR) +} + +func CreateMetric(metric string) *Metric { + switch metric { + case "ASR": + return &ASRMetric{} + case "ACD": + return &ACDMetric{} + case "ACC": + return &ACCMetric{} + } + return nil +} + +// ASR - Answer-Seizure Ratio +// successfully answered Calls divided by the total number of Calls attempted and multiplied by 100 +type ASRMetric struct { + sum float64 + count int64 +} + +func (asr *ASRMetric) AddCdr(cdr *QCDR) { +} + +// ACD – Average Call Duration +// the sum of billable seconds (billsec) of answered calls divided by the number of these answered calls. +type ACDMetric struct { + sum float64 + count int64 +} + +// ACC – Average Call Cost +// the sum of cost of answered calls divided by the number of these answered calls. +type ACCMetric struct { + sum float64 + count int64 +} diff --git a/cdrstats/stats.go b/cdrstats/stats.go new file mode 100644 index 000000000..ac6f509d1 --- /dev/null +++ b/cdrstats/stats.go @@ -0,0 +1,166 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +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 cdrstats + +type StatsQueue struct { + cdrs []*QCDR + config *CdrStatsConfig + metrics map[string]*Metric +} + +// Simplified cdr structure containing only the necessary info +type QCDR struct { + SetupTime time.Time + AnswerTime time.Time + Usage time.Duration + Cost float64 +} + +func NewStatsQueue(config *CdrStatsConfig) *StatsQueue{ + sq := &StatsQueue{ + config:config + metrics:=make(map[string]*Metric, len(config.Metrics)) + } + for _, m := range config.Metrics { + metric := CreateMetric(m) + if metric != nil{ + sq.metrics[m] = metric + } + } +} + +func (sq *StatsQueue) AppendCDR(cdr *utils.StoredCdr){ + if sq.AcceptCDR(cdr){ + qcdr := sq.SimplifyCDR(cdr) + sq.cdrs = append(sq.cdrs, qcdr) + sq.AddToMetrics(qcdr) + } +} + +func (sq *StatsQueue) AddToMetrics(cdr *QCDR) { + for _, metric:= range sq.metrics { + metric.AddCdr(cdr) + } +} + +func (sq *StatsQueue) RemoveFromMetrics(cdr *QCDR) { + for _, metric:= range sq.metrics { + metric.RemoveCdr(cdr) + } +} + +func (sq *StatsQueue) SimplifyCDR(cdr *utils.StoredCdr) *QCDR{ + return &QCDR{ + SetupTime: cdr.SetupTime, + AnswerTime: cdr.AnswerTime, + Usage: cdr.Usage, + Cost: cdr.Cost + } +} + +func (sq *StatsQueue) PurgeObsoleteCDRs { + currentLength := len(sq.cdrs) + if currentLength>sq.config.QueuedItems{ + for _, cdr := range sq.cdrs[:currentLength-sq.config.QueuedItems] { + sq.RemoveFromMetrics(cdr) + } + sq.cdrs = sq.cdrs[currentLength-sq.config.QueuedItems:] + } + for i, cdr := range sq.cdrs { + if time.Now().Sub(cdr.SetupTime) > sq.config.TimeWindow { + sq.RemoveFromMetrics(cdr) + continue + } else { + if i > 0 { + sq.cdrs = sq.cdrs[i:] + } + break + } + } +} + +func (sq *StatsQueue) AcceptCDR(cdr *utils.StoredCdr) bool { + if len(sq.config.SetupInterval) > 0 { + if cdr.SetupTime.Before(sq.config.SetupInterval[0]){ + return false + } + if len(sq.config.SetupInterval) > 1 && (cdr.SetupTime.Equals(sq.config.SetupInterval[1]) || cdr.SetupTime.After(sq.config.SetupInterval[1])){ + return false + } + } + if len(sq.config.TOR) >0 && !utils.IsSliceMember(sq.config.TOR, cdr.TOR){ + return false + } + if len(sq.config.CdrHost) >0 && !utils.IsSliceMember(sq.config.CdrHost, cdr.CdrHost){ + return false + } + if len(sq.config.CdrSource) >0 && !utils.IsSliceMember(sq.config.CdrSource, cdr.CdrSource){ + return false + } + if len(sq.config.ReqType) >0 && !utils.IsSliceMember(sq.config.ReqType, cdr.ReqType){ + return false + } + if len(sq.config.Direction) >0 && !utils.IsSliceMember(sq.config.Direction, cdr.Direction){ + return false + } + if len(sq.config.Tenant) >0 && !utils.IsSliceMember(sq.config.Tenant, cdr.Tenant){ + return false + } + if len(sq.config.Category) >0 && !utils.IsSliceMember(sq.config.Category, cdr.Category){ + return false + } + if len(sq.config.Account) >0 && !utils.IsSliceMember(sq.config.Account, cdr.Account){ + return false + } + if len(sq.config.Subject) >0 && !utils.IsSliceMember(sq.config.Subject, cdr.Subject){ + return false + } + if len(sq.config.DestinationPrefix)>0 { + found := false + for _, prefix := range sq.config.DestinationPrefix { + if cdr.Destination.HasPrefix(prefix){ + found=true + break + } + } + if !found{ + return false + } + } + if len(sq.config.UsageInterval) > 0 { + if cdr.Usage < sq.config.UsageInterval[0]{ + return false + } + if len(sq.config.UsageInterval) > 1 && cdr.Usage >= sq.config.UsageInterval[1]{ + return false + } + } + if len(sq.config.MediationRunIds) >0 && !utils.IsSliceMember(sq.config.MediationRunIds, cdr.MediationRunId){ + return false + } + if len(sq.config.CostInterval) > 0 { + if cdr.Cost < sq.config.CostInterval[0]{ + return false + } + if len(sq.config.CostInterval) > 1 && cdr.Cost >= sq.config.CostInterval[1]{ + return false + } + } + return true +} diff --git a/cdrstats/stats_test.go b/cdrstats/stats_test.go new file mode 100644 index 000000000..e5f85cd13 --- /dev/null +++ b/cdrstats/stats_test.go @@ -0,0 +1,19 @@ +/* +Rating system designed to be used in VoIP Carriers World +Copyright (C) 2013 ITsysCOM + +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 cdrstats diff --git a/config/cdrstatsconfig.go b/config/cdrstatsconfig.go index c234340be..0c9800857 100644 --- a/config/cdrstatsconfig.go +++ b/config/cdrstatsconfig.go @@ -24,7 +24,6 @@ import ( type CdrStatsConfig struct { Id string // Config id, unique per config instance - RatedCdrs bool // Build the stats for rated cdrs instead of raw ones QueuedItems int64 // Number of items in the stats buffer TimeWindow time.Duration // Will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow Metrics []string // ASR, ACD, ACC diff --git a/utils/storedcdr.go b/utils/storedcdr.go index aedd8c057..97d4b3042 100644 --- a/utils/storedcdr.go +++ b/utils/storedcdr.go @@ -1,4 +1,4 @@ -/* + *utilssssss/* Real-time Charging System for Telecom & ISP environments Copyright (C) 2012-2014 ITsysCOM GmbH