mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-24 08:38:45 +05:00
Merge branch 'master' into aliases
This commit is contained in:
@@ -486,7 +486,7 @@ func mailAsync(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) err
|
||||
message = []byte(fmt.Sprintf("To: %s\r\nSubject: [CGR Notification] Threshold hit on Balance: %s\r\n\r\nTime: \r\n\t%s\r\n\r\nBalance:\r\n\t%s\r\n\r\nYours faithfully,\r\nCGR Balance Monitor\r\n", toAddrStr, ub.Id, time.Now(), balJsn))
|
||||
} else if sq != nil {
|
||||
message = []byte(fmt.Sprintf("To: %s\r\nSubject: [CGR Notification] Threshold hit on StatsQueueId: %s\r\n\r\nTime: \r\n\t%s\r\n\r\nStatsQueueId:\r\n\t%s\r\n\r\nMetrics:\r\n\t%+v\r\n\r\nTrigger:\r\n\t%+v\r\n\r\nYours faithfully,\r\nCGR CDR Stats Monitor\r\n",
|
||||
toAddrStr, sq.Id, time.Now(), sq.Id, sq.metrics, sq.Trigger))
|
||||
toAddrStr, sq.Id, time.Now(), sq.Id, sq.Metrics, sq.Trigger))
|
||||
}
|
||||
auth := smtp.PlainAuth("", cgrCfg.MailerAuthUser, cgrCfg.MailerAuthPass, strings.Split(cgrCfg.MailerServer, ":")[0]) // We only need host part, so ignore port
|
||||
go func() {
|
||||
|
||||
@@ -348,22 +348,6 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// split on days
|
||||
/*for i := 0; i < len(timespans); i++ {
|
||||
if timespans[i].TimeStart.Day() != timespans[i].TimeEnd.Day() {
|
||||
//log.Print("TS: ", timespans[i].TimeStart, timespans[i].TimeEnd)
|
||||
start := timespans[i].TimeStart
|
||||
newTs := timespans[i].SplitByTime(time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location()).Add(24 * time.Hour))
|
||||
if newTs != nil {
|
||||
//log.Print("NEW TS: ", newTs.TimeStart, newTs.TimeEnd)
|
||||
// insert the new timespan
|
||||
index := i + 1
|
||||
timespans = append(timespans, nil)
|
||||
copy(timespans[index+1:], timespans[index:])
|
||||
timespans[index] = newTs
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// Logger.Debug(fmt.Sprintf("After SplitByRatingPlan: %+v", timespans))
|
||||
// split on rate intervals
|
||||
for i := 0; i < len(timespans); i++ {
|
||||
@@ -795,7 +779,7 @@ func (cd *CallDescriptor) GetLCRFromStorage() (*LCR, error) {
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
|
||||
func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
func (cd *CallDescriptor) GetLCR(stats StatsInterface, p *utils.Paginator) (*LCRCost, error) {
|
||||
cd.account = nil // make sure it's not cached
|
||||
lcr, err := cd.GetLCRFromStorage()
|
||||
if err != nil {
|
||||
@@ -831,12 +815,13 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
lcrCD.Account = supplier
|
||||
lcrCD.Subject = supplier
|
||||
lcrCD.Category = lcrCost.Entry.RPCategory
|
||||
fullSupplier := utils.ConcatenatedKey(lcrCD.Direction, lcrCD.Tenant, lcrCD.Category, lcrCD.Subject)
|
||||
var cc *CallCost
|
||||
var err error
|
||||
if cd.account, err = accountingStorage.GetAccount(lcrCD.GetAccountKey()); err == nil {
|
||||
if cd.account.Disabled {
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
Error: fmt.Sprintf("supplier %s is disabled", supplier),
|
||||
})
|
||||
continue
|
||||
@@ -846,16 +831,15 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
cc, err = lcrCD.GetCost()
|
||||
|
||||
}
|
||||
supplier = utils.ConcatenatedKey(lcrCD.Direction, lcrCD.Tenant, lcrCD.Category, lcrCD.Subject)
|
||||
//log.Printf("CC: %+v", cc.Timespans[0].ratingInfo.RateIntervals[0].Rating.Rates[0])
|
||||
if err != nil || cc == nil {
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
Error: err.Error(),
|
||||
})
|
||||
} else {
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
Cost: cc.Cost,
|
||||
Duration: cc.GetDuration(),
|
||||
})
|
||||
@@ -878,6 +862,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
lcrCD.Category = category
|
||||
lcrCD.Account = supplier
|
||||
lcrCD.Subject = supplier
|
||||
fullSupplier := utils.ConcatenatedKey(lcrCD.Direction, lcrCD.Tenant, lcrCD.Category, lcrCD.Subject)
|
||||
var qosSortParams []string
|
||||
var asrValues sort.Float64Slice
|
||||
var pddValues sort.Float64Slice
|
||||
@@ -897,7 +882,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
if utils.IsSliceMember([]string{LCR_STRATEGY_QOS, LCR_STRATEGY_QOS_THRESHOLD, LCR_STRATEGY_LOAD}, lcrCost.Entry.Strategy) {
|
||||
if stats == nil {
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
Error: fmt.Sprintf("Cdr stats service not configured"),
|
||||
})
|
||||
continue
|
||||
@@ -905,7 +890,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
rpfKey := utils.ConcatenatedKey(ratingProfileSearchKey, supplier)
|
||||
if rpf, err := ratingStorage.GetRatingProfile(rpfKey, false); err != nil {
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
Error: fmt.Sprintf("Rating plan error: %s", err.Error()),
|
||||
})
|
||||
continue
|
||||
@@ -937,7 +922,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
statValues := make(map[string]float64)
|
||||
if err := stats.GetValues(qId, &statValues); err != nil {
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
Error: fmt.Sprintf("Get stats values for queue id %s, error %s", qId, err.Error()),
|
||||
})
|
||||
statsErr = true
|
||||
@@ -991,7 +976,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
if lcrCost.Entry.Strategy == LCR_STRATEGY_LOAD {
|
||||
if len(supplierQueues) > 0 {
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
supplierQueues: supplierQueues,
|
||||
})
|
||||
}
|
||||
@@ -1071,7 +1056,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
//log.Print("ACCCOUNT")
|
||||
if cd.account.Disabled {
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
Error: fmt.Sprintf("supplier %s is disabled", supplier),
|
||||
})
|
||||
continue
|
||||
@@ -1082,16 +1067,15 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
cc, err = lcrCD.GetCost()
|
||||
}
|
||||
//log.Printf("CC: %+v", cc)
|
||||
supplier = utils.ConcatenatedKey(lcrCD.Direction, lcrCD.Tenant, lcrCD.Category, lcrCD.Subject)
|
||||
if err != nil || cc == nil {
|
||||
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
Error: err.Error(),
|
||||
})
|
||||
continue
|
||||
} else {
|
||||
supplCost := &LCRSupplierCost{
|
||||
Supplier: supplier,
|
||||
Supplier: fullSupplier,
|
||||
Cost: cc.Cost,
|
||||
Duration: cc.GetDuration(),
|
||||
}
|
||||
@@ -1127,5 +1111,13 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
|
||||
// sort according to strategy
|
||||
lcrCost.Sort()
|
||||
}
|
||||
if p != nil {
|
||||
if p.Offset != nil && *p.Offset > 0 && *p.Offset < len(lcrCost.SupplierCosts) {
|
||||
lcrCost.SupplierCosts = lcrCost.SupplierCosts[*p.Offset:]
|
||||
}
|
||||
if p.Limit != nil && *p.Limit > 0 && *p.Limit < len(lcrCost.SupplierCosts) {
|
||||
lcrCost.SupplierCosts = lcrCost.SupplierCosts[:*p.Limit]
|
||||
}
|
||||
}
|
||||
return lcrCost, nil
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ type LcrRequest struct {
|
||||
Destination string
|
||||
StartTime string
|
||||
Duration string
|
||||
*utils.Paginator
|
||||
}
|
||||
|
||||
func (self *LcrRequest) AsCallDescriptor() (*CallDescriptor, error) {
|
||||
|
||||
@@ -204,7 +204,7 @@ func TestLcrGet(t *testing.T) {
|
||||
Account: "rif",
|
||||
Subject: "rif",
|
||||
}
|
||||
lcr, err := cd.GetLCR(nil)
|
||||
lcr, err := cd.GetLCR(nil, nil)
|
||||
//jsn, _ := json.Marshal(lcr)
|
||||
//log.Print("LCR: ", string(jsn))
|
||||
if err != nil || lcr == nil {
|
||||
|
||||
@@ -40,6 +40,11 @@ type SessionRun struct {
|
||||
CallCosts []*CallCost
|
||||
}
|
||||
|
||||
type AttrGetLcr struct {
|
||||
*CallDescriptor
|
||||
*utils.Paginator
|
||||
}
|
||||
|
||||
type Responder struct {
|
||||
Bal *balancer2go.Balancer
|
||||
ExitChan chan bool
|
||||
@@ -325,20 +330,25 @@ func (rs *Responder) LogCallCost(ccl *CallCostLog, reply *string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rs *Responder) GetLCR(cd *CallDescriptor, reply *LCRCost) error {
|
||||
if cd.Subject == "" {
|
||||
cd.Subject = cd.Account
|
||||
func (rs *Responder) GetLCR(attrs *AttrGetLcr, reply *LCRCost) error {
|
||||
if attrs.CallDescriptor.Subject == "" {
|
||||
attrs.CallDescriptor.Subject = attrs.CallDescriptor.Account
|
||||
}
|
||||
if upData, err := LoadUserProfile(cd, "ExtraFields"); err != nil {
|
||||
if upData, err := LoadUserProfile(attrs.CallDescriptor, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*CallDescriptor)
|
||||
*cd = *udRcv
|
||||
*attrs.CallDescriptor = *udRcv
|
||||
}
|
||||
lcrCost, err := cd.GetLCR(rs.Stats)
|
||||
lcrCost, err := attrs.CallDescriptor.GetLCR(rs.Stats, attrs.Paginator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if lcrCost.Entry.Strategy == LCR_STRATEGY_LOAD {
|
||||
for _, suppl := range lcrCost.SupplierCosts {
|
||||
suppl.Cost = -1 // In case of load distribution we don't calculate costs
|
||||
}
|
||||
}
|
||||
*reply = *lcrCost
|
||||
return nil
|
||||
}
|
||||
@@ -505,7 +515,7 @@ type Connector interface {
|
||||
GetSessionRuns(*StoredCdr, *[]*SessionRun) error
|
||||
ProcessCdr(*StoredCdr, *string) error
|
||||
LogCallCost(*CallCostLog, *string) error
|
||||
GetLCR(*CallDescriptor, *LCRCost) error
|
||||
GetLCR(*AttrGetLcr, *LCRCost) error
|
||||
}
|
||||
|
||||
type RPCClientConnector struct {
|
||||
@@ -552,6 +562,6 @@ func (rcc *RPCClientConnector) LogCallCost(ccl *CallCostLog, reply *string) erro
|
||||
return rcc.Client.Call("CDRSV1.LogCallCost", ccl, reply)
|
||||
}
|
||||
|
||||
func (rcc *RPCClientConnector) GetLCR(cd *CallDescriptor, reply *LCRCost) error {
|
||||
return rcc.Client.Call("Responder.GetLCR", cd, reply)
|
||||
func (rcc *RPCClientConnector) GetLCR(attrs *AttrGetLcr, reply *LCRCost) error {
|
||||
return rcc.Client.Call("Responder.GetLCR", attrs, reply)
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ func TestGetLCR(t *testing.T) {
|
||||
},
|
||||
}
|
||||
var lcr LCRCost
|
||||
if err := rsponder.GetLCR(cdStatic, &lcr); err != nil {
|
||||
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdStatic}, &lcr); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eStLcr.Entry, lcr.Entry) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eStLcr.Entry, lcr.Entry)
|
||||
@@ -422,7 +422,7 @@ func TestGetLCR(t *testing.T) {
|
||||
},
|
||||
}
|
||||
var lcrLc LCRCost
|
||||
if err := rsponder.GetLCR(cdLowestCost, &lcrLc); err != nil {
|
||||
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdLowestCost}, &lcrLc); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eLcLcr.Entry, lcrLc.Entry) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eLcLcr.Entry, lcrLc.Entry)
|
||||
@@ -447,7 +447,7 @@ func TestGetLCR(t *testing.T) {
|
||||
&LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second},
|
||||
},
|
||||
}
|
||||
if err := rsponder.GetLCR(cdLowestCost, &lcrLc); err != nil {
|
||||
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdLowestCost}, &lcrLc); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eLcLcr.Entry, lcrLc.Entry) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eLcLcr.Entry, lcrLc.Entry)
|
||||
@@ -476,7 +476,7 @@ func TestGetLCR(t *testing.T) {
|
||||
},
|
||||
}
|
||||
var lcrQT LCRCost
|
||||
if err := rsponder.GetLCR(cdQosThreshold, &lcrQT); err != nil {
|
||||
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry)
|
||||
@@ -495,7 +495,7 @@ func TestGetLCR(t *testing.T) {
|
||||
&LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, QOS: map[string]float64{PDD: -1, ACD: 300, TCD: 300, ASR: 100, ACC: 2, TCC: 2, DDC: 2}, qosSortParams: []string{"35", "4m"}},
|
||||
},
|
||||
}
|
||||
if err := rsponder.GetLCR(cdQosThreshold, &lcrQT); err != nil {
|
||||
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry)
|
||||
@@ -524,7 +524,7 @@ func TestGetLCR(t *testing.T) {
|
||||
},
|
||||
}
|
||||
var lcrQ LCRCost
|
||||
if err := rsponder.GetLCR(cdQos, &lcrQ); err != nil {
|
||||
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQos}, &lcrQ); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eQosLcr.Entry, lcrQ.Entry) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eQosLcr.Entry, lcrQ.Entry)
|
||||
|
||||
@@ -215,12 +215,12 @@ func (sq *StatsQueue) GetId() string {
|
||||
|
||||
// Convert data into a struct which can be used in actions based on triggers hit
|
||||
func (sq *StatsQueue) Triggered(at *ActionTrigger) *StatsQueueTriggered {
|
||||
return &StatsQueueTriggered{Id: sq.conf.Id, metrics: sq.getStats(), Trigger: at}
|
||||
return &StatsQueueTriggered{Id: sq.conf.Id, Metrics: sq.getStats(), Trigger: at}
|
||||
}
|
||||
|
||||
// Struct to be passed to triggered actions
|
||||
type StatsQueueTriggered struct {
|
||||
Id string // StatsQueueId
|
||||
metrics map[string]float64
|
||||
Metrics map[string]float64
|
||||
Trigger *ActionTrigger
|
||||
}
|
||||
|
||||
@@ -416,22 +416,6 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval, data bool) (nts *TimeSp
|
||||
return
|
||||
}
|
||||
|
||||
/*func (ts *TimeSpan) SplitByTime(splitTime time.Time) (nts *TimeSpan) {
|
||||
if splitTime.Equal(ts.TimeEnd) {
|
||||
return
|
||||
}
|
||||
nts = &TimeSpan{
|
||||
TimeStart: splitTime,
|
||||
TimeEnd: ts.TimeEnd,
|
||||
}
|
||||
nts.copyRatingInfo(ts)
|
||||
ts.TimeEnd = splitTime
|
||||
nts.SetRateInterval(ts.RateInterval)
|
||||
nts.DurationIndex = ts.DurationIndex
|
||||
ts.SetNewDurationIndex(nts)
|
||||
return
|
||||
}*/
|
||||
|
||||
// Split the timespan at the given increment start
|
||||
func (ts *TimeSpan) SplitByIncrement(index int) *TimeSpan {
|
||||
if index <= 0 || index >= len(ts.Increments) {
|
||||
|
||||
Reference in New Issue
Block a user