diff --git a/cdre/cdrexporter_test.go b/cdre/cdrexporter_test.go deleted file mode 100644 index 769aeac62..000000000 --- a/cdre/cdrexporter_test.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -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 cdre diff --git a/config/cdreconfig.go b/config/cdreconfig.go index f99dd1fff..d36908ebb 100644 --- a/config/cdreconfig.go +++ b/config/cdreconfig.go @@ -17,19 +17,22 @@ along with this program. If not, see */ package config +import ( + "github.com/cgrates/cgrates/utils" +) + // One instance of CdrExporter type CdreConfig struct { - CdrFormat string - FieldSeparator rune - DataUsageMultiplyFactor float64 - SMSUsageMultiplyFactor float64 - MMSUsageMultiplyFactor float64 - GenericUsageMultiplyFactor float64 - CostMultiplyFactor float64 - ExportDirectory string - HeaderFields []*CfgCdrField - ContentFields []*CfgCdrField - TrailerFields []*CfgCdrField + ExportFormat string + ExportPath string + Synchronous bool + Attempts int + FieldSeparator rune + UsageMultiplyFactor utils.FieldMultiplyFactor + CostMultiplyFactor float64 + HeaderFields []*CfgCdrField + ContentFields []*CfgCdrField + TrailerFields []*CfgCdrField } func (self *CdreConfig) loadFromJsonCfg(jsnCfg *CdreJsonCfg) error { @@ -37,31 +40,33 @@ func (self *CdreConfig) loadFromJsonCfg(jsnCfg *CdreJsonCfg) error { return nil } var err error - if jsnCfg.Cdr_format != nil { - self.CdrFormat = *jsnCfg.Cdr_format + if jsnCfg.Export_format != nil { + self.ExportFormat = *jsnCfg.Export_format + } + if jsnCfg.Export_path != nil { + self.ExportPath = *jsnCfg.Export_path + } + if jsnCfg.Synchronous != nil { + self.Synchronous = *jsnCfg.Synchronous + } + if jsnCfg.Attempts != nil { + self.Attempts = *jsnCfg.Attempts } if jsnCfg.Field_separator != nil && len(*jsnCfg.Field_separator) > 0 { // Make sure we got at least one character so we don't get panic here sepStr := *jsnCfg.Field_separator self.FieldSeparator = rune(sepStr[0]) } - if jsnCfg.Data_usage_multiply_factor != nil { - self.DataUsageMultiplyFactor = *jsnCfg.Data_usage_multiply_factor - } - if jsnCfg.Sms_usage_multiply_factor != nil { - self.SMSUsageMultiplyFactor = *jsnCfg.Sms_usage_multiply_factor - } - if jsnCfg.Mms_usage_multiply_factor != nil { - self.MMSUsageMultiplyFactor = *jsnCfg.Mms_usage_multiply_factor - } - if jsnCfg.Generic_usage_multiply_factor != nil { - self.GenericUsageMultiplyFactor = *jsnCfg.Generic_usage_multiply_factor + if jsnCfg.Usage_multiply_factor != nil { + if self.UsageMultiplyFactor == nil { // not yet initialized + self.UsageMultiplyFactor = make(map[string]float64, len(*jsnCfg.Usage_multiply_factor)) + } + for k, v := range *jsnCfg.Usage_multiply_factor { + self.UsageMultiplyFactor[k] = v + } } if jsnCfg.Cost_multiply_factor != nil { self.CostMultiplyFactor = *jsnCfg.Cost_multiply_factor } - if jsnCfg.Export_directory != nil { - self.ExportDirectory = *jsnCfg.Export_directory - } if jsnCfg.Header_fields != nil { if self.HeaderFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Header_fields); err != nil { return err @@ -83,14 +88,16 @@ func (self *CdreConfig) loadFromJsonCfg(jsnCfg *CdreJsonCfg) error { // Clone itself into a new CdreConfig func (self *CdreConfig) Clone() *CdreConfig { clnCdre := new(CdreConfig) - clnCdre.CdrFormat = self.CdrFormat + clnCdre.ExportFormat = self.ExportFormat + clnCdre.ExportPath = self.ExportPath + clnCdre.Synchronous = self.Synchronous + clnCdre.Attempts = self.Attempts clnCdre.FieldSeparator = self.FieldSeparator - clnCdre.DataUsageMultiplyFactor = self.DataUsageMultiplyFactor - clnCdre.SMSUsageMultiplyFactor = self.SMSUsageMultiplyFactor - clnCdre.MMSUsageMultiplyFactor = self.MMSUsageMultiplyFactor - clnCdre.GenericUsageMultiplyFactor = self.GenericUsageMultiplyFactor + clnCdre.UsageMultiplyFactor = make(map[string]float64, len(self.UsageMultiplyFactor)) + for k, v := range self.UsageMultiplyFactor { + clnCdre.UsageMultiplyFactor[k] = v + } clnCdre.CostMultiplyFactor = self.CostMultiplyFactor - clnCdre.ExportDirectory = self.ExportDirectory clnCdre.HeaderFields = make([]*CfgCdrField, len(self.HeaderFields)) for idx, fld := range self.HeaderFields { clonedVal := *fld diff --git a/config/cdreconfig_test.go b/config/cdreconfig_test.go index a1fe15742..01e63ac9f 100644 --- a/config/cdreconfig_test.go +++ b/config/cdreconfig_test.go @@ -25,8 +25,8 @@ import ( ) func TestCdreCfgClone(t *testing.T) { - cgrIdRsrs, _ := utils.ParseRSRFields("cgrid", utils.INFIELD_SEP) - runIdRsrs, _ := utils.ParseRSRFields("mediation_runid", utils.INFIELD_SEP) + cgrIdRsrs := utils.ParseRSRFieldsMustCompile("cgrid", utils.INFIELD_SEP) + runIdRsrs := utils.ParseRSRFieldsMustCompile("runid", utils.INFIELD_SEP) emptyFields := []*CfgCdrField{} initContentFlds := []*CfgCdrField{ &CfgCdrField{Tag: "CgrId", @@ -35,16 +35,21 @@ func TestCdreCfgClone(t *testing.T) { Value: cgrIdRsrs}, &CfgCdrField{Tag: "RunId", Type: "*composed", - FieldId: "mediation_runid", + FieldId: "runid", Value: runIdRsrs}, } initCdreCfg := &CdreConfig{ - CdrFormat: "csv", - FieldSeparator: rune(','), - DataUsageMultiplyFactor: 1.0, - CostMultiplyFactor: 1.0, - ExportDirectory: "/var/spool/cgrates/cdre", - ContentFields: initContentFlds, + ExportFormat: utils.MetaFileCSV, + ExportPath: "/var/spool/cgrates/cdre", + Synchronous: true, + Attempts: 2, + FieldSeparator: rune(','), + UsageMultiplyFactor: map[string]float64{ + utils.ANY: 1.0, + utils.DATA: 1024, + }, + CostMultiplyFactor: 1.0, + ContentFields: initContentFlds, } eClnContentFlds := []*CfgCdrField{ &CfgCdrField{Tag: "CgrId", @@ -53,24 +58,29 @@ func TestCdreCfgClone(t *testing.T) { Value: cgrIdRsrs}, &CfgCdrField{Tag: "RunId", Type: "*composed", - FieldId: "mediation_runid", + FieldId: "runid", Value: runIdRsrs}, } eClnCdreCfg := &CdreConfig{ - CdrFormat: "csv", - FieldSeparator: rune(','), - DataUsageMultiplyFactor: 1.0, - CostMultiplyFactor: 1.0, - ExportDirectory: "/var/spool/cgrates/cdre", - HeaderFields: emptyFields, - ContentFields: eClnContentFlds, - TrailerFields: emptyFields, + ExportFormat: utils.MetaFileCSV, + ExportPath: "/var/spool/cgrates/cdre", + Synchronous: true, + Attempts: 2, + FieldSeparator: rune(','), + UsageMultiplyFactor: map[string]float64{ + utils.ANY: 1.0, + utils.DATA: 1024.0, + }, + CostMultiplyFactor: 1.0, + HeaderFields: emptyFields, + ContentFields: eClnContentFlds, + TrailerFields: emptyFields, } clnCdreCfg := initCdreCfg.Clone() if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { t.Errorf("Cloned result: %+v", clnCdreCfg) } - initCdreCfg.DataUsageMultiplyFactor = 1024.0 + initCdreCfg.UsageMultiplyFactor[utils.DATA] = 2048.0 if !reflect.DeepEqual(eClnCdreCfg, clnCdreCfg) { // MOdifying a field after clone should not affect cloned instance t.Errorf("Cloned result: %+v", clnCdreCfg) } diff --git a/config/cdrreplication.go b/config/cdrreplication.go deleted file mode 100644 index 370bc6c12..000000000 --- a/config/cdrreplication.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -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 config - -import ( - "github.com/cgrates/cgrates/utils" -) - -type CDRReplicationCfg struct { - Transport string - Address string - Synchronous bool - Attempts int // Number of attempts if not success - CdrFilter utils.RSRFields // Only replicate if the filters here are matching - ContentFields []*CfgCdrField -} - -func (rplCfg CDRReplicationCfg) FallbackFileName() string { - fileSuffix := ".txt" - switch rplCfg.Transport { - case utils.MetaHTTPjsonCDR, utils.MetaHTTPjsonMap, utils.MetaAMQPjsonCDR, utils.MetaAMQPjsonMap: - fileSuffix = ".json" - case utils.META_HTTP_POST: - fileSuffix = ".form" - } - ffn := &utils.FallbackFileName{Module: "cdr", Transport: rplCfg.Transport, Address: rplCfg.Address, - RequestID: utils.GenUUID(), FileSuffix: fileSuffix} - return ffn.AsString() -} diff --git a/config/config.go b/config/config.go index 46cf755be..06110d40c 100644 --- a/config/config.go +++ b/config/config.go @@ -241,14 +241,14 @@ type CGRConfig struct { CDRSStoreCdrs bool // store cdrs in storDb CDRScdrAccountSummary bool CDRSSMCostRetries int - CDRSRaterConns []*HaPoolConfig // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234> - CDRSPubSubSConns []*HaPoolConfig // address where to reach the pubsub service: <""|internal|x.y.z.y:1234> - CDRSUserSConns []*HaPoolConfig // address where to reach the users service: <""|internal|x.y.z.y:1234> - CDRSAliaseSConns []*HaPoolConfig // address where to reach the aliases service: <""|internal|x.y.z.y:1234> - CDRSStatSConns []*HaPoolConfig // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> - CDRSCdrReplication []*CDRReplicationCfg // Replicate raw CDRs to a number of servers - CDRStatsEnabled bool // Enable CDR Stats service - CDRStatsSaveInterval time.Duration // Save interval duration + CDRSRaterConns []*HaPoolConfig // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234> + CDRSPubSubSConns []*HaPoolConfig // address where to reach the pubsub service: <""|internal|x.y.z.y:1234> + CDRSUserSConns []*HaPoolConfig // address where to reach the users service: <""|internal|x.y.z.y:1234> + CDRSAliaseSConns []*HaPoolConfig // address where to reach the aliases service: <""|internal|x.y.z.y:1234> + CDRSStatSConns []*HaPoolConfig // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> + CDRSOnlineCDRExports []string // list of CDRE templates to use for real-time CDR exports + CDRStatsEnabled bool // Enable CDR Stats service + CDRStatsSaveInterval time.Duration // Save interval duration CdreProfiles map[string]*CdreConfig CdrcProfiles map[string][]*CdrcConfig // Number of CDRC instances running imports, format map[dirPath][]{Configs} SmGenericConfig *SmGenericConfig @@ -336,10 +336,9 @@ func (self *CGRConfig) checkConfigSanity() error { return errors.New("CDRStatS not enabled but requested by CDRS component.") } } - for _, rplCfg := range self.CDRSCdrReplication { - if utils.IsSliceMember([]string{utils.MetaHTTPjsonMap, utils.META_HTTP_POST}, rplCfg.Transport) && - len(rplCfg.ContentFields) == 0 { - return fmt.Errorf(" No content fields defined for replication to address: <%s>", rplCfg.Address) + for _, cdrePrfl := range self.CDRSOnlineCDRExports { + if _, hasIt := self.CdreProfiles[cdrePrfl]; !hasIt { + return fmt.Errorf(" Cannot find CDR export template with ID: <%s>", cdrePrfl) } } } @@ -922,33 +921,9 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error { self.CDRSStatSConns[idx].loadFromJsonCfg(jsnHaCfg) } } - if jsnCdrsCfg.Cdr_replication != nil { - self.CDRSCdrReplication = make([]*CDRReplicationCfg, len(*jsnCdrsCfg.Cdr_replication)) - for idx, rplJsonCfg := range *jsnCdrsCfg.Cdr_replication { - self.CDRSCdrReplication[idx] = new(CDRReplicationCfg) - if rplJsonCfg.Transport != nil { - self.CDRSCdrReplication[idx].Transport = *rplJsonCfg.Transport - } - if rplJsonCfg.Address != nil { - self.CDRSCdrReplication[idx].Address = *rplJsonCfg.Address - } - if rplJsonCfg.Synchronous != nil { - self.CDRSCdrReplication[idx].Synchronous = *rplJsonCfg.Synchronous - } - self.CDRSCdrReplication[idx].Attempts = 1 - if rplJsonCfg.Attempts != nil { - self.CDRSCdrReplication[idx].Attempts = *rplJsonCfg.Attempts - } - if rplJsonCfg.Cdr_filter != nil { - if self.CDRSCdrReplication[idx].CdrFilter, err = utils.ParseRSRFields(*rplJsonCfg.Cdr_filter, utils.INFIELD_SEP); err != nil { - return err - } - } - if rplJsonCfg.Content_fields != nil { - if self.CDRSCdrReplication[idx].ContentFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*rplJsonCfg.Content_fields); err != nil { - return err - } - } + if jsnCdrsCfg.Online_cdr_exports != nil { + for _, expProfile := range *jsnCdrsCfg.Online_cdr_exports { + self.CDRSOnlineCDRExports = append(self.CDRSOnlineCDRExports, expProfile) } } } diff --git a/config/config_defaults.go b/config/config_defaults.go index 6d01a8c49..6736c7093 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -153,31 +153,42 @@ const CGRATES_CFG_JSON = ` "users_conns": [], // address where to reach the user service, empty to disable user profile functionality: <""|*internal|x.y.z.y:1234> "aliases_conns": [], // address where to reach the aliases service, empty to disable aliases functionality: <""|*internal|x.y.z.y:1234> "cdrstats_conns": [], // address where to reach the cdrstats service, empty to disable stats functionality<""|*internal|x.y.z.y:1234> - "cdr_replication":[ -// { // sample replication, not configured by default -// "transport": "*amqp_json_map", // mechanism to use when replicating -// "address": "http://127.0.0.1:12080/cdr_json_map", // address where to replicate -// "attempts": 1, // number of attempts for POST before failing on file -// "cdr_filter": "", // filter the CDRs being replicated -// "content_fields": [ // template of the replicated content fields -// {"tag": "CGRID", "type": "*composed", "value": "CGRID", "field_id": "CGRID"}, -// {"tag":"RunID", "type": "*composed", "value": "RunID", "field_id": "RunID"}, -// {"tag":"TOR", "type": "*composed", "value": "ToR", "field_id": "ToR"}, -// {"tag":"OriginID", "type": "*composed", "value": "OriginID", "field_id": "OriginID"}, -// {"tag":"RequestType", "type": "*composed", "value": "RequestType", "field_id": "RequestType"}, -// {"tag":"Direction", "type": "*composed", "value": "Direction", "field_id": "Direction"}, -// {"tag":"Tenant", "type": "*composed", "value": "Tenant", "field_id": "Tenant"}, -// {"tag":"Category", "type": "*composed", "value": "Category", "field_id": "Category"}, -// {"tag":"Account", "type": "*composed", "value": "Account", "field_id": "Account"}, -// {"tag":"Subject", "type": "*composed", "value": "Subject", "field_id": "Subject"}, -// {"tag":"Destination", "type": "*composed", "value": "Destination", "field_id": "Destination"}, -// {"tag":"SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00", "field_id": "SetupTime"}, -// {"tag":"AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00", "field_id": "AnswerTime"}, -// {"tag":"Usage", "type": "*composed", "value": "Usage", "field_id": "Usage"}, -// {"tag":"Cost", "type": "*composed", "value": "Cost", "field_id": "Cost"}, -// ], -// }, - ] + "online_cdr_exports":[], // list of CDRE profiles to use for real-time CDR exports +}, + + +"cdre": { + "*default": { + "export_format": "*file_csv", // exported CDRs format <*file_csv|*file_fwv|*http_post|*http_json_cdr|*http_json_map|*amqp_json_cdr|*amqp_json_map> + "export_path": "/var/spool/cgrates/cdre", // path where the exported CDRs will be placed + "cdr_filter": "", // filter CDRs exported by this template + "synchronous": false, // block processing until export has a result + "attempts": 1, // Number of attempts if not success + "field_separator": ",", // used field separator in some export formats, eg: *file_csv + "usage_multiply_factor": { + "*any": 1 // multiply usage based on ToR field or *any for all + }, + "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT + "header_fields": [], // template of the exported header fields + "content_fields": [ // template of the exported content fields + {"tag": "CGRID", "type": "*composed", "value": "CGRID"}, + {"tag":"RunID", "type": "*composed", "value": "RunID"}, + {"tag":"TOR", "type": "*composed", "value": "ToR"}, + {"tag":"OriginID", "type": "*composed", "value": "OriginID"}, + {"tag":"RequestType", "type": "*composed", "value": "RequestType"}, + {"tag":"Direction", "type": "*composed", "value": "Direction"}, + {"tag":"Tenant", "type": "*composed", "value": "Tenant"}, + {"tag":"Category", "type": "*composed", "value": "Category"}, + {"tag":"Account", "type": "*composed", "value": "Account"}, + {"tag":"Subject", "type": "*composed", "value": "Subject"}, + {"tag":"Destination", "type": "*composed", "value": "Destination"}, + {"tag":"SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"}, + {"tag":"AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"}, + {"tag":"Usage", "type": "*composed", "value": "Usage"}, + {"tag":"Cost", "type": "*composed", "value": "Cost", "rounding_decimals": 4}, + ], + "trailer_fields": [], // template of the exported trailer fields + }, }, @@ -247,39 +258,6 @@ const CGRATES_CFG_JSON = ` ], -"cdre": { - "*default": { - "cdr_format": "csv", // exported CDRs format - "field_separator": ",", - "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes) - "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems) - "mms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from MMS unit to call duration in some billing systems) - "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems) - "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT - "export_directory": "/var/spool/cgrates/cdre", // path where the exported CDRs will be placed - "header_fields": [], // template of the exported header fields - "content_fields": [ // template of the exported content fields - {"tag": "CGRID", "type": "*composed", "value": "CGRID"}, - {"tag":"RunID", "type": "*composed", "value": "RunID"}, - {"tag":"TOR", "type": "*composed", "value": "ToR"}, - {"tag":"OriginID", "type": "*composed", "value": "OriginID"}, - {"tag":"RequestType", "type": "*composed", "value": "RequestType"}, - {"tag":"Direction", "type": "*composed", "value": "Direction"}, - {"tag":"Tenant", "type": "*composed", "value": "Tenant"}, - {"tag":"Category", "type": "*composed", "value": "Category"}, - {"tag":"Account", "type": "*composed", "value": "Account"}, - {"tag":"Subject", "type": "*composed", "value": "Subject"}, - {"tag":"Destination", "type": "*composed", "value": "Destination"}, - {"tag":"SetupTime", "type": "*composed", "value": "SetupTime", "layout": "2006-01-02T15:04:05Z07:00"}, - {"tag":"AnswerTime", "type": "*composed", "value": "AnswerTime", "layout": "2006-01-02T15:04:05Z07:00"}, - {"tag":"Usage", "type": "*composed", "value": "Usage"}, - {"tag":"Cost", "type": "*composed", "value": "Cost", "rounding_decimals": 4}, - ], - "trailer_fields": [], // template of the exported trailer fields - }, -}, - - "sm_generic": { "enabled": false, // starts SessionManager service: "listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests diff --git a/config/config_json_test.go b/config/config_json_test.go index 2cea6d44e..301d0de08 100644 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -203,11 +203,11 @@ func TestDfCdrsJsonCfg(t *testing.T) { &HaPoolJsonCfg{ Address: utils.StringPointer("*internal"), }}, - Pubsubs_conns: &[]*HaPoolJsonCfg{}, - Users_conns: &[]*HaPoolJsonCfg{}, - Aliases_conns: &[]*HaPoolJsonCfg{}, - Cdrstats_conns: &[]*HaPoolJsonCfg{}, - Cdr_replication: &[]*CdrReplicationJsonCfg{}, + Pubsubs_conns: &[]*HaPoolJsonCfg{}, + Users_conns: &[]*HaPoolJsonCfg{}, + Aliases_conns: &[]*HaPoolJsonCfg{}, + Cdrstats_conns: &[]*HaPoolJsonCfg{}, + Online_cdr_exports: &[]string{}, } if cfg, err := dfCgrJsonCfg.CdrsJsonCfg(); err != nil { t.Error(err) @@ -282,17 +282,16 @@ func TestDfCdreJsonCfgs(t *testing.T) { } eCfg := map[string]*CdreJsonCfg{ utils.META_DEFAULT: &CdreJsonCfg{ - Cdr_format: utils.StringPointer("csv"), - Field_separator: utils.StringPointer(","), - Data_usage_multiply_factor: utils.Float64Pointer(1.0), - Sms_usage_multiply_factor: utils.Float64Pointer(1.0), - Mms_usage_multiply_factor: utils.Float64Pointer(1.0), - Generic_usage_multiply_factor: utils.Float64Pointer(1.0), - Cost_multiply_factor: utils.Float64Pointer(1.0), - Export_directory: utils.StringPointer("/var/spool/cgrates/cdre"), - Header_fields: &eFields, - Content_fields: &eContentFlds, - Trailer_fields: &eFields, + Export_format: utils.StringPointer(utils.MetaFileCSV), + Export_path: utils.StringPointer("/var/spool/cgrates/cdre"), + Synchronous: utils.BoolPointer(false), + Attempts: utils.IntPointer(1), + Field_separator: utils.StringPointer(","), + Usage_multiply_factor: &map[string]float64{utils.ANY: 1.0}, + Cost_multiply_factor: utils.Float64Pointer(1.0), + Header_fields: &eFields, + Content_fields: &eContentFlds, + Trailer_fields: &eFields, }, } if cfg, err := dfCgrJsonCfg.CdreJsonCfgs(); err != nil { diff --git a/config/config_test.go b/config/config_test.go index 5bff139c5..98aa6c4fb 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -330,10 +330,7 @@ func TestCgrCfgJSONDefaultsScheduler(t *testing.T) { func TestCgrCfgJSONDefaultsCDRS(t *testing.T) { eHaPoolCfg := []*HaPoolConfig{} - eCDRReCfg := []*CDRReplicationCfg{} - iHaPoolCfg := []*HaPoolConfig{&HaPoolConfig{Address: "*internal"}} var eCdrExtr []*utils.RSRField - if cgrCfg.CDRSEnabled != false { t.Error(cgrCfg.CDRSEnabled) } @@ -349,7 +346,7 @@ func TestCgrCfgJSONDefaultsCDRS(t *testing.T) { if cgrCfg.CDRSSMCostRetries != 5 { t.Error(cgrCfg.CDRSSMCostRetries) } - if !reflect.DeepEqual(cgrCfg.CDRSRaterConns, iHaPoolCfg) { + if !reflect.DeepEqual(cgrCfg.CDRSRaterConns, []*HaPoolConfig{&HaPoolConfig{Address: "*internal"}}) { t.Error(cgrCfg.CDRSRaterConns) } if !reflect.DeepEqual(cgrCfg.CDRSPubSubSConns, eHaPoolCfg) { @@ -364,8 +361,8 @@ func TestCgrCfgJSONDefaultsCDRS(t *testing.T) { if !reflect.DeepEqual(cgrCfg.CDRSStatSConns, eHaPoolCfg) { t.Error(cgrCfg.CDRSStatSConns) } - if !reflect.DeepEqual(cgrCfg.CDRSCdrReplication, eCDRReCfg) { - t.Error(cgrCfg.CDRSCdrReplication) + if cgrCfg.CDRSOnlineCDRExports != nil { + t.Error(cgrCfg.CDRSOnlineCDRExports) } } @@ -399,20 +396,18 @@ func TestCgrCfgJSONDefaultsCdreProfiles(t *testing.T) { } eCdreCfg := map[string]*CdreConfig{ "*default": { - CdrFormat: "csv", - FieldSeparator: ',', - DataUsageMultiplyFactor: 1, - SMSUsageMultiplyFactor: 1, - MMSUsageMultiplyFactor: 1, - GenericUsageMultiplyFactor: 1, - CostMultiplyFactor: 1, - ExportDirectory: "/var/spool/cgrates/cdre", - HeaderFields: eFields, - ContentFields: eContentFlds, - TrailerFields: eFields, + ExportFormat: utils.MetaFileCSV, + ExportPath: "/var/spool/cgrates/cdre", + Synchronous: false, + Attempts: 1, + FieldSeparator: ',', + UsageMultiplyFactor: map[string]float64{utils.ANY: 1.0}, + CostMultiplyFactor: 1.0, + HeaderFields: eFields, + ContentFields: eContentFlds, + TrailerFields: eFields, }, } - if !reflect.DeepEqual(cgrCfg.CdreProfiles, eCdreCfg) { t.Errorf("received: %+v, expecting: %+v", cgrCfg.CdreProfiles, eCdreCfg) } diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 31cb010b3..112a50196 100644 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -104,7 +104,7 @@ type CdrsJsonCfg struct { Users_conns *[]*HaPoolJsonCfg Aliases_conns *[]*HaPoolJsonCfg Cdrstats_conns *[]*HaPoolJsonCfg - Cdr_replication *[]*CdrReplicationJsonCfg + Online_cdr_exports *[]string } type CdrReplicationJsonCfg struct { @@ -145,17 +145,16 @@ type CdrFieldJsonCfg struct { // Cdre config section type CdreJsonCfg struct { - Cdr_format *string - Field_separator *string - Data_usage_multiply_factor *float64 - Sms_usage_multiply_factor *float64 - Mms_usage_multiply_factor *float64 - Generic_usage_multiply_factor *float64 - Cost_multiply_factor *float64 - Export_directory *string - Header_fields *[]*CdrFieldJsonCfg - Content_fields *[]*CdrFieldJsonCfg - Trailer_fields *[]*CdrFieldJsonCfg + Export_format *string + Export_path *string + Synchronous *bool + Attempts *int + Field_separator *string + Usage_multiply_factor *map[string]float64 + Cost_multiply_factor *float64 + Header_fields *[]*CdrFieldJsonCfg + Content_fields *[]*CdrFieldJsonCfg + Trailer_fields *[]*CdrFieldJsonCfg } // Cdrc config section diff --git a/cdre/csv_test.go b/engine/cdrecsv_test.go similarity index 100% rename from cdre/csv_test.go rename to engine/cdrecsv_test.go diff --git a/cdre/fixedwidth_test.go b/engine/cdrefwv_test.go similarity index 100% rename from cdre/fixedwidth_test.go rename to engine/cdrefwv_test.go diff --git a/cdre/cdrexporter.go b/engine/cdrexporter.go similarity index 100% rename from cdre/cdrexporter.go rename to engine/cdrexporter.go diff --git a/utils/map.go b/utils/map.go index 878a4dc54..3e7916119 100644 --- a/utils/map.go +++ b/utils/map.go @@ -205,3 +205,15 @@ func MergeMapsStringIface(mps ...map[string]interface{}) (outMp map[string]inter } return } + +// FieldMultiplyFactor defines multiply factors for different field values +// original defined for CDRE component +type FieldMultiplyFactor map[string]float64 + +func (fmp FieldMultiplyFactor) Clone() (cln FieldMultiplyFactor) { + cln = make(FieldMultiplyFactor, len(fmp)) + for k, v := range fmp { + cln[k] = v + } + return +}