diff --git a/cdrc/cdrc.go b/cdrc/cdrc.go index 8e9c64a73..6aaa89c05 100644 --- a/cdrc/cdrc.go +++ b/cdrc/cdrc.go @@ -130,7 +130,7 @@ func NewCdrc(cdrcCfgs map[string]*config.CdrcConfig, httpSkipTlsCheck bool, cdrs cdrc.cdrSourceIds[idx] = cfg.CdrSourceId cdrc.duMultiplyFactors[idx] = cfg.DataUsageMultiplyFactor cdrc.cdrFilters[idx] = cfg.CdrFilter - cdrc.cdrFields[idx] = cfg.CdrFields + cdrc.cdrFields[idx] = cfg.ContentFields idx += 1 } // Before processing, make sure in and out folders exist @@ -249,6 +249,8 @@ func (self *Cdrc) processFile(filePath string) error { csvReader.Comma = self.csvSep recordsProcessor = NewCsvRecordsProcessor(csvReader, self.cdrFormat, fn, self.failedCallsPrefix, self.cdrSourceIds, self.duMultiplyFactors, self.cdrFilters, self.cdrFields, self.httpSkipTlsCheck, self.partialRecordsCache) + } else if self.cdrFormat == utils.FWV { + recordsProcessor = NewFwvRecordsProcessor(file) } procRowNr := 0 timeStart := time.Now() diff --git a/cdrc/csv_test.go b/cdrc/csv_test.go index 7044362ca..c122ab332 100644 --- a/cdrc/csv_test.go +++ b/cdrc/csv_test.go @@ -31,10 +31,10 @@ import ( func TestCsvRecordForkCdr(t *testing.T) { cgrConfig, _ := config.NewDefaultCGRConfig() cdrcConfig := cgrConfig.CdrcProfiles["/var/log/cgrates/cdrc/in"][utils.META_DEFAULT] - cdrcConfig.CdrFields = append(cdrcConfig.CdrFields, &config.CfgCdrField{Tag: "SupplierTest", Type: utils.CDRFIELD, CdrFieldId: "supplier", Value: []*utils.RSRField{&utils.RSRField{Id: "14"}}}) - cdrcConfig.CdrFields = append(cdrcConfig.CdrFields, &config.CfgCdrField{Tag: "DisconnectCauseTest", Type: utils.CDRFIELD, CdrFieldId: utils.DISCONNECT_CAUSE, + cdrcConfig.ContentFields = append(cdrcConfig.ContentFields, &config.CfgCdrField{Tag: "SupplierTest", Type: utils.CDRFIELD, CdrFieldId: "supplier", Value: []*utils.RSRField{&utils.RSRField{Id: "14"}}}) + cdrcConfig.ContentFields = append(cdrcConfig.ContentFields, &config.CfgCdrField{Tag: "DisconnectCauseTest", Type: utils.CDRFIELD, CdrFieldId: utils.DISCONNECT_CAUSE, Value: []*utils.RSRField{&utils.RSRField{Id: "16"}}}) - csvProcessor := &CsvRecordsProcessor{cdrFormat: CSV, cdrSourceIds: []string{"TEST_CDRC"}, cdrFields: [][]*config.CfgCdrField{cdrcConfig.CdrFields}} + csvProcessor := &CsvRecordsProcessor{cdrFormat: CSV, cdrSourceIds: []string{"TEST_CDRC"}, cdrFields: [][]*config.CfgCdrField{cdrcConfig.ContentFields}} cdrRow := []string{"firstField", "secondField"} _, err := csvProcessor.recordToStoredCdr(cdrRow, 0) if err == nil { diff --git a/config/cdrcconfig.go b/config/cdrcconfig.go index 3ab32cad6..5555d0096 100644 --- a/config/cdrcconfig.go +++ b/config/cdrcconfig.go @@ -38,7 +38,9 @@ type CdrcConfig struct { CdrSourceId string // Source identifier for the processed CDRs CdrFilter utils.RSRFields // Filter CDR records to import PartialRecordCache time.Duration // Duration to cache partial records when not pairing - CdrFields []*CfgCdrField // List of fields to be processed + HeaderFields []*CfgCdrField + ContentFields []*CfgCdrField + TrailerFields []*CfgCdrField } func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error { @@ -90,8 +92,18 @@ func (self *CdrcConfig) loadFromJsonCfg(jsnCfg *CdrcJsonCfg) error { return err } } - if jsnCfg.Cdr_fields != nil { - if self.CdrFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Cdr_fields); err != nil { + if jsnCfg.Header_fields != nil { + if self.HeaderFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Header_fields); err != nil { + return err + } + } + if jsnCfg.Content_fields != nil { + if self.ContentFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Content_fields); err != nil { + return err + } + } + if jsnCfg.Trailer_fields != nil { + if self.TrailerFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Trailer_fields); err != nil { return err } } @@ -111,10 +123,20 @@ func (self *CdrcConfig) Clone() *CdrcConfig { clnCdrc.CdrInDir = self.CdrInDir clnCdrc.CdrOutDir = self.CdrOutDir clnCdrc.CdrSourceId = self.CdrSourceId - clnCdrc.CdrFields = make([]*CfgCdrField, len(self.CdrFields)) - for idx, fld := range self.CdrFields { + clnCdrc.HeaderFields = make([]*CfgCdrField, len(self.HeaderFields)) + clnCdrc.ContentFields = make([]*CfgCdrField, len(self.ContentFields)) + clnCdrc.TrailerFields = make([]*CfgCdrField, len(self.TrailerFields)) + for idx, fld := range self.HeaderFields { clonedVal := *fld - clnCdrc.CdrFields[idx] = &clonedVal + clnCdrc.HeaderFields[idx] = &clonedVal + } + for idx, fld := range self.ContentFields { + clonedVal := *fld + clnCdrc.ContentFields[idx] = &clonedVal + } + for idx, fld := range self.TrailerFields { + clonedVal := *fld + clnCdrc.TrailerFields[idx] = &clonedVal } return clnCdrc } diff --git a/config/cfg_data.json b/config/cfg_data.json index 9f7e9c6f3..6ff5f9b70 100644 --- a/config/cfg_data.json +++ b/config/cfg_data.json @@ -32,7 +32,7 @@ "data_usage_multiply_factor": 0.000976563, "run_delay": 1, "cdr_source_id": "csv2", // free form field, tag identifying the source of the CDRs within CDRS database - "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value {"cdr_field_id": "tor", "value": "~7:s/^(voice|data|sms|generic)$/*$1/"}, {"cdr_field_id": "answer_time", "value": "1"}, {"cdr_field_id": "usage", "value": "~9:s/^(\\d+)$/${1}s/"}, diff --git a/config/cfg_data2.json b/config/cfg_data2.json index 1865dc713..0fb070c8b 100644 --- a/config/cfg_data2.json +++ b/config/cfg_data2.json @@ -7,7 +7,7 @@ "cdr_out_dir": "/tmp/cgrates/cdrc2/out", // absolute path towards the directory where processed CDRs will be moved "data_usage_multiply_factor": 0.000976563, "cdr_source_id": "csv2", // free form field, tag identifying the source of the CDRs within CDRS database - "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value {"cdr_field_id": "tor", "value": "~7:s/^(voice|data|sms|generic)$/*$1/"}, {"cdr_field_id": "answer_time", "value": "2"}, ], diff --git a/config/config.go b/config/config.go index 69bfd0d0b..c299ae9ec 100644 --- a/config/config.go +++ b/config/config.go @@ -273,11 +273,11 @@ func (self *CGRConfig) checkConfigSanity() error { } else if cdrcInst.Cdrs == utils.INTERNAL && !self.CDRSEnabled { return errors.New("CDRS not enabled but referenced from CDRC") } - if len(cdrcInst.CdrFields) == 0 { + if len(cdrcInst.ContentFields) == 0 { return errors.New("CdrC enabled but no fields to be processed defined!") } if cdrcInst.CdrFormat == utils.CSV { - for _, cdrFld := range cdrcInst.CdrFields { + for _, cdrFld := range cdrcInst.ContentFields { for _, rsrFld := range cdrFld.Value { if _, errConv := strconv.Atoi(rsrFld.Id); errConv != nil && !rsrFld.IsStatic() { return fmt.Errorf("CDR fields must be indices in case of .csv files, have instead: %s", rsrFld.Id) diff --git a/config/config_defaults.go b/config/config_defaults.go index d7e4166d4..0a67020e1 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -168,7 +168,8 @@ const CGRATES_CFG_JSON = ` "cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database "cdr_filter": "", // filter CDR records to import "partial_record_cache": "10s", // duration to cache partial records when not pairing - "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + "header_fields": [], // template of the import header fields + "content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value {"tag": "tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "2", "mandatory": true}, {"tag": "accid", "cdr_field_id": "accid", "type": "cdrfield", "value": "3", "mandatory": true}, {"tag": "reqtype", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "4", "mandatory": true}, @@ -182,6 +183,7 @@ const CGRATES_CFG_JSON = ` {"tag": "answer_time", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "12", "mandatory": true}, {"tag": "usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "13", "mandatory": true}, ], + "trailer_fields": [], // template of the import trailer fields } }, diff --git a/config/config_json_test.go b/config/config_json_test.go index 696965792..1a5741fd3 100644 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -259,6 +259,7 @@ func TestDfCdreJsonCfgs(t *testing.T) { } func TestDfCdrcJsonCfg(t *testing.T) { + eFields := []*CdrFieldJsonCfg{} cdrFields := []*CdrFieldJsonCfg{ &CdrFieldJsonCfg{Tag: utils.StringPointer("tor"), Cdr_field_id: utils.StringPointer("tor"), Type: utils.StringPointer(utils.CDRFIELD), Value: utils.StringPointer("2"), Mandatory: utils.BoolPointer(true)}, @@ -300,13 +301,15 @@ func TestDfCdrcJsonCfg(t *testing.T) { Cdr_source_id: utils.StringPointer("freeswitch_csv"), Cdr_filter: utils.StringPointer(""), Partial_record_cache: utils.StringPointer("10s"), - Cdr_fields: &cdrFields, + Header_fields: &eFields, + Content_fields: &cdrFields, + Trailer_fields: &eFields, }, } if cfg, err := dfCgrJsonCfg.CdrcJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfg, cfg) { - t.Error("Received: ", cfg) + t.Error("Received: ", cfg["*default"]) } } @@ -423,6 +426,7 @@ func TestDfUserServJsonCfg(t *testing.T) { } func TestDfMailerJsonCfg(t *testing.T) { + eCfg := &MailerJsonCfg{ Server: utils.StringPointer("localhost"), Auth_user: utils.StringPointer("cgrates"), @@ -466,15 +470,14 @@ func TestNewCgrJsonCfgFromFile(t *testing.T) { Cdr_in_dir: utils.StringPointer("/tmp/cgrates/cdrc2/in"), Cdr_out_dir: utils.StringPointer("/tmp/cgrates/cdrc2/out"), Cdr_source_id: utils.StringPointer("csv2"), - Cdr_fields: &cdrFields, + Content_fields: &cdrFields, }, } if cfg, err := cgrJsonCfg.CdrcJsonCfg(); err != nil { t.Error(err) } else if !reflect.DeepEqual(eCfgCdrc, cfg) { - t.Error("Received: ", cfg) + t.Error("Received: ", cfg["CDRC-CSV2"]) } - eCfgSmFs := &SmFsJsonCfg{ Enabled: utils.BoolPointer(true), Connections: &[]*FsConnJsonCfg{ diff --git a/config/configcdrc_test.go b/config/configcdrc_test.go index 7daa55543..bfc7c8948 100644 --- a/config/configcdrc_test.go +++ b/config/configcdrc_test.go @@ -49,7 +49,8 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { CdrSourceId: "freeswitch_csv", CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), PartialRecordCache: time.Duration(10) * time.Second, - CdrFields: []*CfgCdrField{ + HeaderFields: make([]*CfgCdrField, 0), + ContentFields: []*CfgCdrField{ &CfgCdrField{Tag: "tor", Type: "cdrfield", CdrFieldId: "tor", Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, &CfgCdrField{Tag: "accid", Type: "cdrfield", CdrFieldId: "accid", Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), @@ -75,6 +76,7 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { &CfgCdrField{Tag: "usage", Type: "cdrfield", CdrFieldId: "usage", Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP), FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, }, + TrailerFields: make([]*CfgCdrField, 0), }, } eCgrCfg.CdrcProfiles["/tmp/cgrates/cdrc1/in"] = map[string]*CdrcConfig{ @@ -90,7 +92,8 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { CdrOutDir: "/tmp/cgrates/cdrc1/out", CdrSourceId: "csv1", CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), - CdrFields: []*CfgCdrField{ + HeaderFields: make([]*CfgCdrField, 0), + ContentFields: []*CfgCdrField{ &CfgCdrField{Tag: "tor", Type: "cdrfield", CdrFieldId: "tor", Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, &CfgCdrField{Tag: "accid", Type: "cdrfield", CdrFieldId: "accid", Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), @@ -116,6 +119,7 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { &CfgCdrField{Tag: "usage", Type: "cdrfield", CdrFieldId: "usage", Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP), FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, }, + TrailerFields: make([]*CfgCdrField, 0), }, } eCgrCfg.CdrcProfiles["/tmp/cgrates/cdrc2/in"] = map[string]*CdrcConfig{ @@ -131,12 +135,14 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { CdrOutDir: "/tmp/cgrates/cdrc2/out", CdrSourceId: "csv2", CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), - CdrFields: []*CfgCdrField{ + HeaderFields: make([]*CfgCdrField, 0), + ContentFields: []*CfgCdrField{ &CfgCdrField{Tag: "", Type: "", CdrFieldId: "tor", Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|generic)$/*$1/", utils.INFIELD_SEP), FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false}, &CfgCdrField{Tag: "", Type: "", CdrFieldId: "answer_time", Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: false}, }, + TrailerFields: make([]*CfgCdrField, 0), }, } eCgrCfg.CdrcProfiles["/tmp/cgrates/cdrc3/in"] = map[string]*CdrcConfig{ @@ -152,7 +158,8 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { CdrOutDir: "/tmp/cgrates/cdrc3/out", CdrSourceId: "csv3", CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), - CdrFields: []*CfgCdrField{ + HeaderFields: make([]*CfgCdrField, 0), + ContentFields: []*CfgCdrField{ &CfgCdrField{Tag: "tor", Type: "cdrfield", CdrFieldId: "tor", Value: utils.ParseRSRFieldsMustCompile("2", utils.INFIELD_SEP), FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, &CfgCdrField{Tag: "accid", Type: "cdrfield", CdrFieldId: "accid", Value: utils.ParseRSRFieldsMustCompile("3", utils.INFIELD_SEP), @@ -178,6 +185,7 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { &CfgCdrField{Tag: "usage", Type: "cdrfield", CdrFieldId: "usage", Value: utils.ParseRSRFieldsMustCompile("13", utils.INFIELD_SEP), FieldFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), Width: 0, Strip: "", Padding: "", Layout: "", Mandatory: true}, }, + TrailerFields: make([]*CfgCdrField, 0), }, } if !reflect.DeepEqual(eCgrCfg.CdrcProfiles, cgrCfg.CdrcProfiles) { diff --git a/config/libconfig_json.go b/config/libconfig_json.go index c1c6b8a37..73d03376d 100644 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -139,7 +139,9 @@ type CdrcJsonCfg struct { Cdr_filter *string Max_open_files *int Partial_record_cache *string - Cdr_fields *[]*CdrFieldJsonCfg + Header_fields *[]*CdrFieldJsonCfg + Content_fields *[]*CdrFieldJsonCfg + Trailer_fields *[]*CdrFieldJsonCfg } // SM-FreeSWITCH config section diff --git a/data/conf/cgrates/cgrates.json b/data/conf/cgrates/cgrates.json index 7921f6647..5781bdaf1 100644 --- a/data/conf/cgrates/cgrates.json +++ b/data/conf/cgrates/cgrates.json @@ -148,7 +148,8 @@ // "cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database // "cdr_filter": "", // filter CDR records to import // "partial_record_cache": "10s", // duration to cache partial records when not pairing -// "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value +// "header_fields": [], // template of the import header fields +// "content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value // {"tag": "tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "2", "mandatory": true}, // {"tag": "accid", "cdr_field_id": "accid", "type": "cdrfield", "value": "3", "mandatory": true}, // {"tag": "reqtype", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "4", "mandatory": true}, @@ -162,7 +163,8 @@ // {"tag": "answer_time", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "12", "mandatory": true}, // {"tag": "usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "13", "mandatory": true}, // ], -// }, +// "trailer_fields": [], // template of the import trailer fields +// } //}, diff --git a/data/conf/samples/cdrcflatstore/cgrates.json b/data/conf/samples/cdrcflatstore/cgrates.json index 6c8b77a78..454a5db8a 100644 --- a/data/conf/samples/cdrcflatstore/cgrates.json +++ b/data/conf/samples/cdrcflatstore/cgrates.json @@ -24,20 +24,20 @@ "cdrc": { "FLATSTORE": { - "enabled": true, // enable CDR client functionality - "cdrs": "internal", // address where to reach CDR server. - "cdr_format": "opensips_flatstore", // CDR file format - "field_separator": "|", // separator used in case of csv files - "run_delay": 0, // sleep interval in seconds between consecutive runs, 0 to use automation via inotify - "max_open_files": 1024, // maximum simultaneous files to process - "data_usage_multiply_factor": 1024, // conversion factor for data usage - "cdr_in_dir": "/tmp/cgr_flatstore/cdrc/in", // absolute path towards the directory where the CDRs are stored + "enabled": true, // enable CDR client functionality + "cdrs": "internal", // address where to reach CDR server. + "cdr_format": "opensips_flatstore", // CDR file format + "field_separator": "|", // separator used in case of csv files + "run_delay": 0, // sleep interval in seconds between consecutive runs, 0 to use automation via inotify + "max_open_files": 1024, // maximum simultaneous files to process + "data_usage_multiply_factor": 1024, // conversion factor for data usage + "cdr_in_dir": "/tmp/cgr_flatstore/cdrc/in", // absolute path towards the directory where the CDRs are stored "cdr_out_dir": "/tmp/cgr_flatstore/cdrc/out", // absolute path towards the directory where processed CDRs will be moved - "failed_calls_prefix": "missed_calls", // used in case of flatstore CDRs to avoid searching for BYE records - "cdr_source_id": "flatstore", // free form field, tag identifying the source of the CDRs within CDRS database - "cdr_filter": "", // filter CDR records to import - "partial_record_cache": "1s", // duration to cache partial records when not pairing - "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + "failed_calls_prefix": "missed_calls", // used in case of flatstore CDRs to avoid searching for BYE records + "cdr_source_id": "flatstore", // free form field, tag identifying the source of the CDRs within CDRS database + "cdr_filter": "", // filter CDR records to import + "partial_record_cache": "1s", // duration to cache partial records when not pairing + "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value {"tag": "Tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "^*voice", "mandatory": true}, {"tag": "AccId", "cdr_field_id": "accid", "type": "cdrfield", "mandatory": true}, {"tag": "ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "7", "mandatory": true}, diff --git a/data/conf/samples/fscsv/freeswitch_csvcdr.json b/data/conf/samples/fscsv/freeswitch_csvcdr.json index 80056fbb4..b20f3c3f4 100644 --- a/data/conf/samples/fscsv/freeswitch_csvcdr.json +++ b/data/conf/samples/fscsv/freeswitch_csvcdr.json @@ -7,7 +7,7 @@ "cdr_in_dir": "/tmp/cgrates/cdrc_fs/in", // absolute path towards the directory where the CDRs are stored "cdr_out_dir": "/tmp/cgrates/cdrc_fs/out", // absolute path towards the directory where processed CDRs will be moved "cdr_source_id": "fs_csv", // free form field, tag identifying the source of the CDRs within CDRS database - "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value {"tag": "tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "^*voice", "mandatory": true}, {"tag": "accid", "cdr_field_id": "accid", "type": "cdrfield", "value": "10", "mandatory": true}, {"tag": "reqtype", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "^rated", "mandatory": true}, diff --git a/data/conf/samples/multiplecdrc/multiplecdrc_fwexport.json b/data/conf/samples/multiplecdrc/multiplecdrc_fwexport.json index 4422923c0..d6285e750 100644 --- a/data/conf/samples/multiplecdrc/multiplecdrc_fwexport.json +++ b/data/conf/samples/multiplecdrc/multiplecdrc_fwexport.json @@ -29,7 +29,7 @@ "cdr_in_dir": "/tmp/cgrates/cdrc2/in", // absolute path towards the directory where the CDRs are stored "cdr_out_dir": "/tmp/cgrates/cdrc2/out", // absolute path towards the directory where processed CDRs will be moved "cdr_source_id": "csv2", // free form field, tag identifying the source of the CDRs within CDRS database - "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value {"cdr_field_id": "tor", "value": "~7:s/^(voice|data|sms|generic)$/*$1/"}, {"cdr_field_id": "accid", "value": "0"}, {"cdr_field_id": "reqtype", "value": "^rated"}, @@ -50,7 +50,7 @@ "cdr_in_dir": "/tmp/cgrates/cdrc3/in", // absolute path towards the directory where the CDRs are stored "cdr_out_dir": "/tmp/cgrates/cdrc3/out", // absolute path towards the directory where processed CDRs will be moved "cdr_source_id": "csv3", // free form field, tag identifying the source of the CDRs within CDRS database - "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value {"cdr_field_id": "tor", "value": "^*voice"}, {"cdr_field_id": "accid", "value": "~3:s/^(\\d{2})\\.(\\d{2})\\.(\\d{4})\\s{2}(\\d{2}):(\\d{2}):(\\d{2})$/$1$2$3$4$5$6/"}, {"cdr_field_id": "reqtype", "value": "^rated"}, diff --git a/data/tutorials/fs_evsock/cgrates/etc/cgrates/cdrc_fs.json b/data/tutorials/fs_evsock/cgrates/etc/cgrates/cdrc_fs.json index f56c72677..0baddf735 100644 --- a/data/tutorials/fs_evsock/cgrates/etc/cgrates/cdrc_fs.json +++ b/data/tutorials/fs_evsock/cgrates/etc/cgrates/cdrc_fs.json @@ -7,7 +7,7 @@ "cdr_in_dir": "/tmp/cgr_fsevsock/cgrates/cdrc/in", // absolute path towards the directory where the CDRs are stored "cdr_out_dir": "/tmp/cgr_fsevsock/cgrates/cdrc/out", // absolute path towards the directory where processed CDRs will be moved "cdr_source_id": "fs_csv", // free form field, tag identifying the source of the CDRs within CDRS database - "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value {"tag": "tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "^*voice", "mandatory": true}, {"tag": "accid", "cdr_field_id": "accid", "type": "cdrfield", "value": "10", "mandatory": true}, {"tag": "reqtype", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "^*pseudoprepaid", "mandatory": true}, diff --git a/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json b/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json index be348859a..dc7d624a9 100644 --- a/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json +++ b/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json @@ -184,7 +184,7 @@ // "cdr_out_dir": "/var/log/cgrates/cdrc/out", // absolute path towards the directory where processed CDRs will be moved // "cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database // "cdr_filter": "", // Filter CDR records to import -// "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value +// "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value // {"tag": "tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "2", "mandatory": true}, // {"tag": "accid", "cdr_field_id": "accid", "type": "cdrfield", "value": "3", "mandatory": true}, // {"tag": "reqtype", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "4", "mandatory": true}, diff --git a/utils/consts.go b/utils/consts.go index 1f8c65349..4fe6e2e3a 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -123,6 +123,7 @@ const ( META_DEFAULT = "*default" STATIC_VALUE_PREFIX = "^" CSV = "csv" + FWV = "fwv" DRYRUN = "dry_run" COMBIMED = "combimed" INTERNAL = "internal"