From e4a4732fee9db51af73d03e6ff9aec98adde59d9 Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 30 Apr 2015 13:28:59 +0200 Subject: [PATCH] Dynamic template for *cgrlog, RSRFields instead of RSRField in extra_params --- engine/action.go | 84 ++++++++++++++++++++++++++++-------- engine/actions_local_test.go | 3 ++ engine/actions_test.go | 39 +++++++++++++++-- 3 files changed, 106 insertions(+), 20 deletions(-) diff --git a/engine/action.go b/engine/action.go index 206f3666b..b15f6a3d5 100644 --- a/engine/action.go +++ b/engine/action.go @@ -128,11 +128,64 @@ func logAction(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (er return } +// Used by cdrLogAction to dynamically parse values out of account and action +func parseTemplateValue(rsrFlds utils.RSRFields, acnt *Account, action *Action) string { + dta, err := utils.NewDTAFromAccountKey(acnt.Id) // Account information should be valid + if err != nil { + dta = new(utils.DirectionTenantAccount) // Init with empty values + } + var parsedValue string // Template values + for _, rsrFld := range rsrFlds { + switch rsrFld.Id { + case "account_id": + parsedValue += rsrFld.ParseValue(acnt.Id) + case "direction": + parsedValue += rsrFld.ParseValue(dta.Direction) + case "tenant": + parsedValue += rsrFld.ParseValue(dta.Tenant) + case "account": + parsedValue += rsrFld.ParseValue(dta.Account) + case "action_id": + parsedValue += rsrFld.ParseValue(action.Id) + case "action_type": + parsedValue += rsrFld.ParseValue(action.ActionType) + case "balance_type": + parsedValue += rsrFld.ParseValue(action.BalanceType) + case "balance_uuid": + parsedValue += rsrFld.ParseValue(action.Balance.Uuid) + case "balance_id": + parsedValue += rsrFld.ParseValue(action.Balance.Id) + case "balance_value": + parsedValue += rsrFld.ParseValue(strconv.FormatFloat(action.Balance.Value, 'f', -1, 64)) + case "destination_id": + parsedValue += rsrFld.ParseValue(action.Balance.DestinationId) + case "extra_params": + parsedValue += rsrFld.ParseValue(action.ExtraParameters) + case "rating_subject": + parsedValue += rsrFld.ParseValue(action.Balance.RatingSubject) + case "category": + parsedValue += rsrFld.ParseValue(action.Balance.Category) + case "shared_group": + parsedValue += rsrFld.ParseValue(action.Balance.SharedGroup) + default: + parsedValue += rsrFld.ParseValue("") // Mostly for static values + } + } + return parsedValue +} + func cdrLogAction(acc *Account, sq *StatsQueueTriggered, a *Action, acs Actions) (err error) { - defaultTemplate := map[string]*utils.RSRField{ - "CdrHost": utils.ParseRSRFieldsMustCompile("^127.0.0.1", utils.INFIELD_SEP)[0], - "ReqType": utils.ParseRSRFieldsMustCompile("^"+utils.META_PREPAID, utils.INFIELD_SEP)[0], - "MediationRunId": utils.ParseRSRFieldsMustCompile("^"+utils.META_DEFAULT, utils.INFIELD_SEP)[0], + + defaultTemplate := map[string]utils.RSRFields{ + "TOR": utils.ParseRSRFieldsMustCompile("balance_type", utils.INFIELD_SEP), + "CdrHost": utils.ParseRSRFieldsMustCompile("^127.0.0.1", utils.INFIELD_SEP), + "Direction": utils.ParseRSRFieldsMustCompile("direction", utils.INFIELD_SEP), + "ReqType": utils.ParseRSRFieldsMustCompile("^"+utils.META_PREPAID, utils.INFIELD_SEP), + "Tenant": utils.ParseRSRFieldsMustCompile("tenant", utils.INFIELD_SEP), + "Account": utils.ParseRSRFieldsMustCompile("account", utils.INFIELD_SEP), + "Subject": utils.ParseRSRFieldsMustCompile("account", utils.INFIELD_SEP), + "Cost": utils.ParseRSRFieldsMustCompile("balance_value", utils.INFIELD_SEP), + "MediationRunId": utils.ParseRSRFieldsMustCompile("^"+utils.META_DEFAULT, utils.INFIELD_SEP), } template := make(map[string]string) @@ -142,7 +195,7 @@ func cdrLogAction(acc *Account, sq *StatsQueueTriggered, a *Action, acs Actions) return } for field, rsr := range template { - defaultTemplate[field], err = utils.NewRSRField(rsr) + defaultTemplate[field], err = utils.ParseRSRFields(rsr, utils.INFIELD_SEP) if err != nil { return err } @@ -152,35 +205,32 @@ func cdrLogAction(acc *Account, sq *StatsQueueTriggered, a *Action, acs Actions) // set stored cdr values var cdrs []*StoredCdr for _, action := range acs { - if !utils.IsSliceMember([]string{DEBIT, DEBIT_RESET}, action.ActionType) { + if !utils.IsSliceMember([]string{DEBIT, DEBIT_RESET}, action.ActionType) || action.Balance == nil { continue // Only log specific actions } - cdr := &StoredCdr{CdrSource: CDRLOG, SetupTime: time.Now(), AnswerTime: time.Now(), AccId: utils.GenUUID()} + cdr := &StoredCdr{CdrSource: CDRLOG, SetupTime: time.Now(), AnswerTime: time.Now(), AccId: utils.GenUUID(), ExtraFields: make(map[string]string)} cdr.CgrId = utils.Sha1(cdr.AccId, cdr.SetupTime.String()) cdr.Usage = time.Duration(1) * time.Second elem := reflect.ValueOf(cdr).Elem() - for key, rsr := range defaultTemplate { + for key, rsrFlds := range defaultTemplate { + parsedValue := parseTemplateValue(rsrFlds, acc, action) field := elem.FieldByName(key) if field.IsValid() && field.CanSet() { switch field.Kind() { case reflect.Float64: - value, err := strconv.ParseFloat(rsr.ParseValue(""), 64) + value, err := strconv.ParseFloat(parsedValue, 64) if err != nil { continue } field.SetFloat(value) case reflect.String: - field.SetString(rsr.ParseValue("")) + field.SetString(parsedValue) } + } else { // invalid fields go in extraFields of CDR + cdr.ExtraFields[key] = parsedValue } } - // Hardcode the data for now, expand it with templates later - cdr.TOR = action.BalanceType - cdr.Direction = action.Direction - if action.Balance != nil { - cdr.Cost = action.Balance.Value - } - Logger.Debug(fmt.Sprintf("action: %+v, balance: %+v", action, action.Balance)) + //Logger.Debug(fmt.Sprintf("account: %+v, action: %+v, balance: %+v", acc, action, action.Balance)) cdrs = append(cdrs, cdr) if cdrStorage == nil { // Only save if the cdrStorage is defined continue diff --git a/engine/actions_local_test.go b/engine/actions_local_test.go index d9ea80cb5..1fbbb1664 100644 --- a/engine/actions_local_test.go +++ b/engine/actions_local_test.go @@ -111,6 +111,9 @@ func TestActionsLocalSetCdrlogActions(t *testing.T) { rcvedCdrs[0].CdrHost != "127.0.0.1" || rcvedCdrs[0].CdrSource != CDRLOG || rcvedCdrs[0].ReqType != utils.META_PREPAID || + rcvedCdrs[0].Tenant != "cgrates.org" || + rcvedCdrs[0].Account != "dan2904" || + rcvedCdrs[0].Subject != "dan2904" || rcvedCdrs[0].Usage != "1" || rcvedCdrs[0].MediationRunId != utils.META_DEFAULT || rcvedCdrs[0].Cost != attrsAA.Actions[0].Units { diff --git a/engine/actions_test.go b/engine/actions_test.go index 9f3d367b6..e24887d5b 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -1113,12 +1113,14 @@ func TestTopupActionLoaded(t *testing.T) { } func TestActionCdrlogEmpty(t *testing.T) { + acnt := &Account{Id: "*out:cgrates.org:dan2904"} cdrlog := &Action{ ActionType: CDRLOG, } - err := cdrLogAction(nil, nil, cdrlog, Actions{ + err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, + Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, }, }) if err != nil { @@ -1132,16 +1134,19 @@ func TestActionCdrlogEmpty(t *testing.T) { } func TestActionCdrlogWithParams(t *testing.T) { + acnt := &Account{Id: "*out:cgrates.org:dan2904"} cdrlog := &Action{ ActionType: CDRLOG, - ExtraParameters: `{"Account":"^dan","Subject": "^rif","Destination":"^1234","Tor":"~action_tag:s/^at(.)$/0$1/"}`, + ExtraParameters: `{"ReqType":"^*pseudoprepaid","Subject":"^rif", "TOR":"~action_type:s/^\\*(.*)$/did_$1/"}`, } - err := cdrLogAction(nil, nil, cdrlog, Actions{ + err := cdrLogAction(acnt, nil, cdrlog, Actions{ &Action{ ActionType: DEBIT, + Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, }, &Action{ ActionType: DEBIT_RESET, + Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, }, }) if err != nil { @@ -1155,6 +1160,34 @@ func TestActionCdrlogWithParams(t *testing.T) { } } +/* +func TestActionCdrLogParamsOverload(t *testing.T) { + cdrlog := &Action{ + ActionType: CDRLOG, + ExtraParameters: `{"Account":"^dan","Subject": "^rif","Destination":"^1234","Tor":"~action_tag:s/^at(.)$/0$1/"}`, + } + err := cdrLogAction(nil, nil, cdrlog, Actions{ + &Action{ + ActionType: DEBIT, + Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + }, + &Action{ + ActionType: DEBIT_RESET, + Balance: &Balance{Value: 25, DestinationId: "RET", Weight: 20}, + }, + }) + if err != nil { + t.Error("Error performing cdrlog action: ", err) + } + cdrs := make([]*StoredCdr, 0) + json.Unmarshal([]byte(cdrlog.ExpirationString), &cdrs) + if len(cdrs) != 2 || + cdrs[0].Subject != "rif" { + t.Errorf("Wrong cdrlogs: %+v", cdrs[0]) + } +} +*/ + /********************************** Benchmarks ********************************/ func BenchmarkUUID(b *testing.B) {