mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Adding FieldMultiplyFactor so we can clone it centralized
This commit is contained in:
@@ -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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
package cdre
|
||||
@@ -17,19 +17,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
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()
|
||||
}
|
||||
@@ -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("<CDRS> 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("<CDRS> 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <csv>
|
||||
"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: <true|false>
|
||||
"listen_bijson": "127.0.0.1:2014", // address where to listen for bidirectional JSON-RPC requests
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
12
utils/map.go
12
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user