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
+}