diff --git a/apier/v1/apier.go b/apier/v1/apier.go
index a1e7771f2..eb7aad2a4 100644
--- a/apier/v1/apier.go
+++ b/apier/v1/apier.go
@@ -29,6 +29,7 @@ import (
"time"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/guardian"
"github.com/cgrates/cgrates/scheduler"
@@ -453,11 +454,11 @@ func (apierSv1 *APIerSv1) ImportTariffPlanFromFolder(attrs *utils.AttrImportTPFr
// SetRatingProfile sets a specific rating profile working with data directly in the DataDB without involving storDb
func (apierSv1 *APIerSv1) SetRatingProfile(attrs *utils.AttrSetRatingProfile, reply *string) (err error) {
- if missing := utils.MissingStructFields(attrs, []string{"ToR", "Subject", "RatingPlanActivations"}); len(missing) != 0 {
+ if missing := utils.MissingStructFields(attrs, []string{"Subject", "RatingPlanActivations"}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
for _, rpa := range attrs.RatingPlanActivations {
- if missing := utils.MissingStructFields(rpa, []string{"ActivationTimes", "RatingPlanId"}); len(missing) != 0 {
+ if missing := utils.MissingStructFields(rpa, []string{"ActivationTime", "RatingPlanId"}); len(missing) != 0 {
return fmt.Errorf("%s:RatingPlanActivation:%v", utils.ErrMandatoryIeMissing.Error(), missing)
}
}
@@ -1404,7 +1405,7 @@ func (apierSv1 *APIerSv1) ReplayFailedPosts(args *ArgsReplyFailedPosts, reply *s
}
}
filePath := path.Join(failedReqsInDir, file.Name())
- expEv, err := engine.NewExportEventsFromFile(filePath)
+ expEv, err := ees.NewExportEventsFromFile(filePath)
if err != nil {
return utils.NewErrServerError(err)
}
diff --git a/apier/v1/apier_it_test.go b/apier/v1/apier_it_test.go
index fc4602f3b..482c5fd1e 100644
--- a/apier/v1/apier_it_test.go
+++ b/apier/v1/apier_it_test.go
@@ -35,6 +35,7 @@ import (
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/dispatchers"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/scheduler"
"github.com/cgrates/cgrates/servmanager"
@@ -71,81 +72,81 @@ var (
testApierInitStorDb,
testApierStartEngine,
testApierRpcConn,
- testApierTPTiming,
- testApierTPDestination,
- testApierTPRate,
- testApierTPDestinationRate,
- testApierTPRatingPlan,
- testApierTPRatingProfile,
- testApierTPActions,
- testApierTPActionPlan,
- testApierTPActionTriggers,
- testApierTPAccountActions,
- testApierLoadRatingPlan,
- testApierLoadRatingProfile,
- testApierLoadRatingProfileWithoutTenant,
- testApierLoadAccountActions,
- testApierReloadScheduler,
- testApierSetRatingProfile,
- testApierSetRatingProfileWithoutTenant,
- testApierRemoveRatingProfilesWithoutTenant,
- testAPIerSv1GetRatingProfile,
- testAPIerSv1GetRatingProfileWithoutTenant,
- testAPIerSv1GetRatingProfileIDsWithoutTenant,
- testApierReloadCache,
- testApierGetActionTrigger,
- testApierGetDestination,
- testApierGetRatingPlan,
- testApierRemoveRatingPlan,
- testApierAddBalance,
- testApierExecuteAction,
- testApierExecuteActionWithoutTenant,
- testApierSetActions,
- testApierGetActions,
- testApierSetActionPlan,
- testApierAddTriggeredAction,
- testApierGetAccountActionTriggers,
- testApierAddTriggeredAction2,
- testApierGetAccountActionTriggers2,
- testApierSetAccountActionTriggers,
- testApierRemAccountActionTriggers,
- testApierSetAccount,
- testApierGetAccountActionPlan,
- testApierGetAccountActionPlanWithoutTenant,
- testApierITGetScheduledActionsForAccount,
- testApierRemUniqueIDActionTiming,
- testApierRemUniqueIDActionTimingWithoutTenant,
- testApierGetAccount,
- testApierTriggersExecute,
- testApierResetDataBeforeLoadFromFolder,
- testApierLoadTariffPlanFromFolder,
- testApierComputeReverse,
- testApierResetDataAfterLoadFromFolder,
- testApierSetChargerS,
- testApierGetAccountAfterLoad,
- testApierResponderGetCost,
- testApierMaxDebitInexistentAcnt,
- testApierCdrServer,
- testApierITGetCdrs,
- testApierITProcessCdr,
- testApierGetCallCostLog,
- testApierITSetDestination,
- testApierITGetScheduledActions,
- testApierITGetDataCost,
- testApierITGetCost,
+ // testApierTPTiming,
+ // testApierTPDestination,
+ // testApierTPRate,
+ // testApierTPDestinationRate,
+ // testApierTPRatingPlan,
+ // testApierTPRatingProfile,
+ // testApierTPActions,
+ // testApierTPActionPlan,
+ // testApierTPActionTriggers,
+ // testApierTPAccountActions,
+ // testApierLoadRatingPlan,
+ // testApierLoadRatingProfile,
+ // testApierLoadRatingProfileWithoutTenant,
+ // testApierLoadAccountActions,
+ // testApierReloadScheduler,
+ // testApierSetRatingProfile,
+ // testApierSetRatingProfileWithoutTenant,
+ // testApierRemoveRatingProfilesWithoutTenant,
+ // testAPIerSv1GetRatingProfile,
+ // testAPIerSv1GetRatingProfileWithoutTenant,
+ // testAPIerSv1GetRatingProfileIDsWithoutTenant,
+ // testApierReloadCache,
+ // testApierGetActionTrigger,
+ // testApierGetDestination,
+ // testApierGetRatingPlan,
+ // testApierRemoveRatingPlan,
+ // testApierAddBalance,
+ // testApierExecuteAction,
+ // testApierExecuteActionWithoutTenant,
+ // testApierSetActions,
+ // testApierGetActions,
+ // testApierSetActionPlan,
+ // testApierAddTriggeredAction,
+ // testApierGetAccountActionTriggers,
+ // testApierAddTriggeredAction2,
+ // testApierGetAccountActionTriggers2,
+ // testApierSetAccountActionTriggers,
+ // testApierRemAccountActionTriggers,
+ // testApierSetAccount,
+ // testApierGetAccountActionPlan,
+ // testApierGetAccountActionPlanWithoutTenant,
+ // testApierITGetScheduledActionsForAccount,
+ // testApierRemUniqueIDActionTiming,
+ // testApierRemUniqueIDActionTimingWithoutTenant,
+ // testApierGetAccount,
+ // testApierTriggersExecute,
+ // testApierResetDataBeforeLoadFromFolder,
+ // testApierLoadTariffPlanFromFolder,
+ // testApierComputeReverse,
+ // testApierResetDataAfterLoadFromFolder,
+ // testApierSetChargerS,
+ // testApierGetAccountAfterLoad,
+ // testApierResponderGetCost,
+ // testApierMaxDebitInexistentAcnt,
+ // testApierCdrServer,
+ // testApierITGetCdrs,
+ // testApierITProcessCdr,
+ // testApierGetCallCostLog,
+ // testApierITSetDestination,
+ // testApierITGetScheduledActions,
+ // testApierITGetDataCost,
+ // testApierITGetCost,
testApierInitDataDb2,
testApierInitStorDb2,
- testApierReloadCache2,
- testApierReloadScheduler2,
- testApierImportTPFromFolderPath,
- testApierLoadTariffPlanFromStorDbDryRun,
- testApierGetCacheStats2,
- testApierLoadTariffPlanFromStorDb,
- testApierStartStopServiceStatus,
+ // testApierReloadCache2,
+ // testApierReloadScheduler2,
+ // testApierImportTPFromFolderPath,
+ // testApierLoadTariffPlanFromStorDbDryRun,
+ // testApierGetCacheStats2,
+ // testApierLoadTariffPlanFromStorDb,
+ // testApierStartStopServiceStatus,
testApierReplayFldPosts,
- testApierGetDataDBVesions,
- testApierGetStorDBVesions,
- testApierBackwardsCompatible,
+ // testApierGetDataDBVesions,
+ // testApierGetStorDBVesions,
+ // testApierBackwardsCompatible,
testApierStopEngine,
}
)
@@ -2109,10 +2110,10 @@ func testApierRemoveRatingProfilesWithoutTenant(t *testing.T) {
func testApierReplayFldPosts(t *testing.T) {
bev := []byte(`{"ID":"cgrates.org:1007","BalanceMap":{"*monetary":[{"Uuid":"367be35a-96ee-40a5-b609-9130661f5f12","ID":"","Value":0,"ExpirationDate":"0001-01-01T00:00:00Z","Weight":10,"DestinationIDs":{},"RatingSubject":"","Categories":{},"SharedGroups":{"SHARED_A":true},"Timings":null,"TimingIDs":{},"Disabled":false,"Factor":null,"Blocker":false}]},"UnitCounters":{"*monetary":[{"CounterType":"*event","Counters":[{"Value":0,"Filter":{"Uuid":null,"ID":"b8531413-10d5-47ad-81ad-2bc272e8f0ca","Type":"*monetary","Value":null,"ExpirationDate":null,"Weight":null,"DestinationIDs":{"FS_USERS":true},"RatingSubject":null,"Categories":null,"SharedGroups":null,"TimingIDs":null,"Timings":null,"Disabled":null,"Factor":null,"Blocker":null}}]}]},"ActionTriggers":[{"ID":"STANDARD_TRIGGERS","UniqueID":"46ac7b8c-685d-4555-bf73-fa6cfbc2fa21","ThresholdType":"*min_balance","ThresholdValue":2,"Recurrent":false,"MinSleep":0,"ExpirationDate":"0001-01-01T00:00:00Z","ActivationDate":"0001-01-01T00:00:00Z","Balance":{"Uuid":null,"ID":null,"Type":"*monetary","Value":null,"ExpirationDate":null,"Weight":null,"DestinationIDs":null,"RatingSubject":null,"Categories":null,"SharedGroups":null,"TimingIDs":null,"Timings":null,"Disabled":null,"Factor":null,"Blocker":null},"Weight":10,"ActionsID":"LOG_WARNING","MinQueuedItems":0,"Executed":true,"LastExecutionTime":"2017-01-31T14:03:57.961651647+01:00"},{"ID":"STANDARD_TRIGGERS","UniqueID":"b8531413-10d5-47ad-81ad-2bc272e8f0ca","ThresholdType":"*max_event_counter","ThresholdValue":5,"Recurrent":false,"MinSleep":0,"ExpirationDate":"0001-01-01T00:00:00Z","ActivationDate":"0001-01-01T00:00:00Z","Balance":{"Uuid":null,"ID":null,"Type":"*monetary","Value":null,"ExpirationDate":null,"Weight":null,"DestinationIDs":{"FS_USERS":true},"RatingSubject":null,"Categories":null,"SharedGroups":null,"TimingIDs":null,"Timings":null,"Disabled":null,"Factor":null,"Blocker":null},"Weight":10,"ActionsID":"LOG_WARNING","MinQueuedItems":0,"Executed":false,"LastExecutionTime":"0001-01-01T00:00:00Z"},{"ID":"STANDARD_TRIGGERS","UniqueID":"8b424186-7a31-4aef-99c5-35e12e6fed41","ThresholdType":"*max_balance","ThresholdValue":20,"Recurrent":false,"MinSleep":0,"ExpirationDate":"0001-01-01T00:00:00Z","ActivationDate":"0001-01-01T00:00:00Z","Balance":{"Uuid":null,"ID":null,"Type":"*monetary","Value":null,"ExpirationDate":null,"Weight":null,"DestinationIDs":null,"RatingSubject":null,"Categories":null,"SharedGroups":null,"TimingIDs":null,"Timings":null,"Disabled":null,"Factor":null,"Blocker":null},"Weight":10,"ActionsID":"LOG_WARNING","MinQueuedItems":0,"Executed":false,"LastExecutionTime":"0001-01-01T00:00:00Z"},{"ID":"STANDARD_TRIGGERS","UniqueID":"28557f3b-139c-4a27-9d17-bda1f54b7c19","ThresholdType":"*max_balance","ThresholdValue":100,"Recurrent":false,"MinSleep":0,"ExpirationDate":"0001-01-01T00:00:00Z","ActivationDate":"0001-01-01T00:00:00Z","Balance":{"Uuid":null,"ID":null,"Type":"*monetary","Value":null,"ExpirationDate":null,"Weight":null,"DestinationIDs":null,"RatingSubject":null,"Categories":null,"SharedGroups":null,"TimingIDs":null,"Timings":null,"Disabled":null,"Factor":null,"Blocker":null},"Weight":10,"ActionsID":"DISABLE_AND_LOG","MinQueuedItems":0,"Executed":false,"LastExecutionTime":"0001-01-01T00:00:00Z"}],"AllowNegative":false,"Disabled":false}"`)
- ev := &engine.ExportEvents{
+ ev := &ees.ExportEvents{
Path: "http://localhost:2081",
- Format: utils.MetaHTTPjson,
- Events: []interface{}{&engine.HTTPPosterRequest{Body: bev, Header: http.Header{"Content-Type": []string{"application/json"}}}},
+ Format: utils.MetaHTTPjsonMap,
+ Events: []interface{}{&ees.HTTPPosterRequest{Body: bev, Header: http.Header{"Content-Type": []string{"application/json"}}}},
}
fileName := "act>*http_post|63bed4ea-615e-4096-b1f4-499f64f29b28.json"
@@ -2139,7 +2140,7 @@ func testApierReplayFldPosts(t *testing.T) {
t.Error("Unexpected reply: ", reply)
}
outPath := path.Join(*args.FailedRequestsOutDir, fileName)
- outEv, err := engine.NewExportEventsFromFile(outPath)
+ outEv, err := ees.NewExportEventsFromFile(outPath)
if err != nil {
t.Error(err)
} else if !reflect.DeepEqual(ev, outEv) {
@@ -2148,7 +2149,7 @@ func testApierReplayFldPosts(t *testing.T) {
fileName = "cdr|ae8cc4b3-5e60-4396-b82a-64b96a72a03c.json"
bev = []byte(`{"CGRID":"88ed9c38005f07576a1e1af293063833b60edcc6"}`)
fileInPath := path.Join(*args.FailedRequestsInDir, fileName)
- ev = &engine.ExportEvents{
+ ev = &ees.ExportEvents{
Path: "amqp://guest:guest@localhost:5672/",
Opts: map[string]interface{}{
utils.AMQPQueueID: "cgrates_cdrs",
diff --git a/apier/v1/config_it_test.go b/apier/v1/config_it_test.go
index 96c2624b4..432566908 100644
--- a/apier/v1/config_it_test.go
+++ b/apier/v1/config_it_test.go
@@ -384,6 +384,7 @@ func testConfigSSetConfigEEs(t *testing.T) {
"type": "*none",
"opts": map[string]interface{}{},
"concurrent_requests": 0.,
+ "failed_posts_dir": "/var/spool/cgrates/failed_posts",
}
exp := map[string]interface{}{
"enabled": true,
diff --git a/apier/v1/tpchargers.go b/apier/v1/tpchargers.go
index 2ed8a7d43..073b4e8e1 100644
--- a/apier/v1/tpchargers.go
+++ b/apier/v1/tpchargers.go
@@ -63,7 +63,7 @@ type AttrGetTPChargerIds struct {
// GetTPChargerIDs queries Charger identities on specific tariff plan.
func (apierSv1 *APIerSv1) GetTPChargerIDs(attrs *AttrGetTPChargerIds, reply *[]string) error {
- if missing := utils.MissingStructFields(attrs, []string{utils.ID}); len(missing) != 0 { //Params missing
+ if missing := utils.MissingStructFields(attrs, []string{utils.TPid}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
ids, err := apierSv1.StorDb.GetTpTableIds(attrs.TPid, utils.TBLTPChargers, utils.TPDistinctIds{utils.TenantCfg, utils.IDCfg},
diff --git a/apier/v2/tpdestinations.go b/apier/v2/tpdestinations.go
index c5b627055..c46efb20c 100644
--- a/apier/v2/tpdestinations.go
+++ b/apier/v2/tpdestinations.go
@@ -24,7 +24,7 @@ import (
// Creates a new destination within a tariff plan
func (self *APIerSv2) SetTPDestination(attrs *utils.TPDestination, reply *string) error {
- if missing := utils.MissingStructFields(attrs, []string{"TPid", "Tag", "Prefixes"}); len(missing) != 0 { //Params missing
+ if missing := utils.MissingStructFields(attrs, []string{"TPid", "ID", "Prefixes"}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
if err := self.StorDb.SetTPDestinations([]*utils.TPDestination{attrs}); err != nil {
diff --git a/config/config_defaults.go b/config/config_defaults.go
index a3de3a37c..3d7baac95 100644
--- a/config/config_defaults.go
+++ b/config/config_defaults.go
@@ -577,6 +577,7 @@ const CGRATES_CFG_JSON = `
"synchronous": false, // block processing until export has a result
"attempts": 1, // export attempts
"fields":[], // import fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
+ "failed_posts_dir": "/var/spool/cgrates/failed_posts", // directory path where we store failed requests
},
],
},
diff --git a/config/config_json_test.go b/config/config_json_test.go
index 9ddc9dca1..20acc4db7 100644
--- a/config/config_json_test.go
+++ b/config/config_json_test.go
@@ -1887,6 +1887,7 @@ func TestDfEventExporterCfg(t *testing.T) {
Fields: &[]*FcTemplateJsonCfg{},
Opts: make(map[string]interface{}),
Concurrent_requests: utils.IntPointer(0),
+ Failed_posts_dir: utils.StringPointer("/var/spool/cgrates/failed_posts"),
},
},
}
diff --git a/config/config_test.go b/config/config_test.go
index 8a3087147..c4cde9825 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -2392,19 +2392,20 @@ func TestEEsNoLksConfig(t *testing.T) {
},
Exporters: []*EventExporterCfg{
{
- ID: utils.MetaDefault,
- Type: utils.MetaNone,
- ExportPath: "/var/spool/cgrates/ees",
- Attempts: 1,
- Timezone: utils.EmptyString,
- Filters: []string{},
- AttributeSIDs: []string{},
- Flags: utils.FlagsWithParams{},
- contentFields: []*FCTemplate{},
- Fields: []*FCTemplate{},
- headerFields: []*FCTemplate{},
- trailerFields: []*FCTemplate{},
- Opts: make(map[string]interface{}),
+ ID: utils.MetaDefault,
+ Type: utils.MetaNone,
+ ExportPath: "/var/spool/cgrates/ees",
+ Attempts: 1,
+ Timezone: utils.EmptyString,
+ Filters: []string{},
+ AttributeSIDs: []string{},
+ Flags: utils.FlagsWithParams{},
+ contentFields: []*FCTemplate{},
+ Fields: []*FCTemplate{},
+ headerFields: []*FCTemplate{},
+ trailerFields: []*FCTemplate{},
+ Opts: make(map[string]interface{}),
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
},
},
}
@@ -4364,6 +4365,7 @@ func TestV1GetConfigSectionEES(t *testing.T) {
utils.AttemptsCfg: 1,
utils.FieldsCfg: []map[string]interface{}{},
utils.ConcurrentRequestsCfg: 0,
+ utils.FailedPostsDirCfg: "/var/spool/cgrates/failed_posts",
},
},
},
@@ -5055,7 +5057,7 @@ func TestV1GetConfigAsJSONApierS(t *testing.T) {
func TestV1GetConfigAsJSONCfgEES(t *testing.T) {
var reply string
- expected := `{"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]}}`
+ expected := `{"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]}}`
cgrCfg := NewDefaultCGRConfig()
if err := cgrCfg.V1GetConfigAsJSON(&SectionWithAPIOpts{Section: EEsJson}, &reply); err != nil {
t.Error(err)
@@ -5234,7 +5236,7 @@ func TestV1GetConfigAsJSONAllConfig(t *testing.T) {
}
}`
var reply string
- expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"enabled":false,"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"any_context":true,"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"process_runs":1,"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*accounts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*apiban":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*attribute_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*caps_events":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*cdr_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*cdrs":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*charger_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*charger_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*closed_sessions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*diameter_messages":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_loads":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatchers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*event_charges":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*load_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*replication_hosts":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resource_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resource_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*reverse_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*reverse_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*route_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*route_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rpc_connections":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rpc_responses":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*session_costs":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*stat_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*statqueue_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*statqueues":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*stir":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*threshold_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_account_actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_attributes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_chargers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_destination_rates":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rates":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_stats":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*uch":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*versions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""}},"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"remote":false,"replicate":false},"*accounts":{"remote":false,"replicate":false},"*action_plans":{"remote":false,"replicate":false},"*action_triggers":{"remote":false,"replicate":false},"*actions":{"remote":false,"replicate":false},"*attribute_profiles":{"remote":false,"replicate":false},"*charger_profiles":{"remote":false,"replicate":false},"*destinations":{"remote":false,"replicate":false},"*dispatcher_hosts":{"remote":false,"replicate":false},"*dispatcher_profiles":{"remote":false,"replicate":false},"*filters":{"remote":false,"replicate":false},"*indexes":{"remote":false,"replicate":false},"*load_ids":{"remote":false,"replicate":false},"*rating_plans":{"remote":false,"replicate":false},"*rating_profiles":{"remote":false,"replicate":false},"*resource_profiles":{"remote":false,"replicate":false},"*resources":{"remote":false,"replicate":false},"*reverse_destinations":{"remote":false,"replicate":false},"*route_profiles":{"remote":false,"replicate":false},"*shared_groups":{"remote":false,"replicate":false},"*statqueue_profiles":{"remote":false,"replicate":false},"*statqueues":{"remote":false,"replicate":false},"*threshold_profiles":{"remote":false,"replicate":false},"*thresholds":{"remote":false,"replicate":false},"*timings":{"remote":false,"replicate":false}},"opts":{"mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0","redisClusterSync":"5s","redisSentinel":"","redisTLS":false},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listen":"127.0.0.1:2053","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime","xmlRootPath":""},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","password":"ClueCon","reconnects":5}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0","forceAttemptHttp2":true,"idleConnTimeout":"90s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"ConnectAttempts","tag":"ConnectAttempts","type":"*variable","value":"~*req.4"},{"path":"Reconnects","tag":"Reconnects","type":"*variable","value":"~*req.5"},{"path":"ConnectTimeout","tag":"ConnectTimeout","type":"*variable","value":"~*req.6"},{"path":"ReplyTimeout","tag":"ReplyTimeout","type":"*variable","value":"~*req.7"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.8"},{"path":"ClientKey","tag":"ClientKey","type":"*variable","value":"~*req.9"},{"path":"ClientCertificate","tag":"ClientCertificate","type":"*variable","value":"~*req.10"},{"path":"CaCertificate","tag":"CaCertificate","type":"*variable","value":"~*req.11"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lock_filename":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0","redisClusterSync":"5s","redisSentinel":"","redisTLS":false},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"mysql","out_stordb_user":"cgrates","users_filters":[]},"radius_agent":{"client_dictionaries":{"*default":"/usr/share/cgrates/radius/dict/"},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"stats_conns":[],"thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"rals_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"schedulers":{"cdrs_conns":[],"dynaprepaid_actionplans":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"remote":false,"replicate":false},"*session_costs":{"remote":false,"replicate":false},"*tp_account_actions":{"remote":false,"replicate":false},"*tp_action_plans":{"remote":false,"replicate":false},"*tp_action_triggers":{"remote":false,"replicate":false},"*tp_actions":{"remote":false,"replicate":false},"*tp_attributes":{"remote":false,"replicate":false},"*tp_chargers":{"remote":false,"replicate":false},"*tp_destination_rates":{"remote":false,"replicate":false},"*tp_destinations":{"remote":false,"replicate":false},"*tp_dispatcher_hosts":{"remote":false,"replicate":false},"*tp_dispatcher_profiles":{"remote":false,"replicate":false},"*tp_filters":{"remote":false,"replicate":false},"*tp_rates":{"remote":false,"replicate":false},"*tp_rating_plans":{"remote":false,"replicate":false},"*tp_rating_profiles":{"remote":false,"replicate":false},"*tp_resources":{"remote":false,"replicate":false},"*tp_routes":{"remote":false,"replicate":false},"*tp_shared_groups":{"remote":false,"replicate":false},"*tp_stats":{"remote":false,"replicate":false},"*tp_thresholds":{"remote":false,"replicate":false},"*tp_timings":{"remote":false,"replicate":false},"*versions":{"remote":false,"replicate":false}},"opts":{"mongoQueryTimeout":"10s","mysqlLocation":"Local","postgresSSLMode":"disable","sqlConnMaxLifetime":0,"sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}`
+ expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"enabled":false,"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"any_context":true,"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"process_runs":1,"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*accounts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*apiban":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*attribute_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*caps_events":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*cdr_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*cdrs":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*charger_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*charger_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*closed_sessions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*diameter_messages":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_loads":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatcher_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*dispatchers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*event_charges":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*load_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*replication_hosts":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resource_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resource_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*reverse_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*reverse_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*route_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*route_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rpc_connections":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*rpc_responses":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*session_costs":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*stat_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*statqueue_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*statqueues":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*stir":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*threshold_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_account_actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_attributes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_chargers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_destination_rates":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rates":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_stats":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*tp_timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""},"*uch":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*versions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":""}},"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"remote":false,"replicate":false},"*accounts":{"remote":false,"replicate":false},"*action_plans":{"remote":false,"replicate":false},"*action_triggers":{"remote":false,"replicate":false},"*actions":{"remote":false,"replicate":false},"*attribute_profiles":{"remote":false,"replicate":false},"*charger_profiles":{"remote":false,"replicate":false},"*destinations":{"remote":false,"replicate":false},"*dispatcher_hosts":{"remote":false,"replicate":false},"*dispatcher_profiles":{"remote":false,"replicate":false},"*filters":{"remote":false,"replicate":false},"*indexes":{"remote":false,"replicate":false},"*load_ids":{"remote":false,"replicate":false},"*rating_plans":{"remote":false,"replicate":false},"*rating_profiles":{"remote":false,"replicate":false},"*resource_profiles":{"remote":false,"replicate":false},"*resources":{"remote":false,"replicate":false},"*reverse_destinations":{"remote":false,"replicate":false},"*route_profiles":{"remote":false,"replicate":false},"*shared_groups":{"remote":false,"replicate":false},"*statqueue_profiles":{"remote":false,"replicate":false},"*statqueues":{"remote":false,"replicate":false},"*threshold_profiles":{"remote":false,"replicate":false},"*thresholds":{"remote":false,"replicate":false},"*timings":{"remote":false,"replicate":false}},"opts":{"mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0","redisClusterSync":"5s","redisSentinel":"","redisTLS":false},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listen":"127.0.0.1:2053","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime","xmlRootPath":""},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","password":"ClueCon","reconnects":5}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0","forceAttemptHttp2":true,"idleConnTimeout":"90s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"ConnectAttempts","tag":"ConnectAttempts","type":"*variable","value":"~*req.4"},{"path":"Reconnects","tag":"Reconnects","type":"*variable","value":"~*req.5"},{"path":"ConnectTimeout","tag":"ConnectTimeout","type":"*variable","value":"~*req.6"},{"path":"ReplyTimeout","tag":"ReplyTimeout","type":"*variable","value":"~*req.7"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.8"},{"path":"ClientKey","tag":"ClientKey","type":"*variable","value":"~*req.9"},{"path":"ClientCertificate","tag":"ClientCertificate","type":"*variable","value":"~*req.10"},{"path":"CaCertificate","tag":"CaCertificate","type":"*variable","value":"~*req.11"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lock_filename":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0","redisClusterSync":"5s","redisSentinel":"","redisTLS":false},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"mysql","out_stordb_user":"cgrates","users_filters":[]},"radius_agent":{"client_dictionaries":{"*default":"/usr/share/cgrates/radius/dict/"},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"stats_conns":[],"thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"rals_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"schedulers":{"cdrs_conns":[],"dynaprepaid_actionplans":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"remote":false,"replicate":false},"*session_costs":{"remote":false,"replicate":false},"*tp_account_actions":{"remote":false,"replicate":false},"*tp_action_plans":{"remote":false,"replicate":false},"*tp_action_triggers":{"remote":false,"replicate":false},"*tp_actions":{"remote":false,"replicate":false},"*tp_attributes":{"remote":false,"replicate":false},"*tp_chargers":{"remote":false,"replicate":false},"*tp_destination_rates":{"remote":false,"replicate":false},"*tp_destinations":{"remote":false,"replicate":false},"*tp_dispatcher_hosts":{"remote":false,"replicate":false},"*tp_dispatcher_profiles":{"remote":false,"replicate":false},"*tp_filters":{"remote":false,"replicate":false},"*tp_rates":{"remote":false,"replicate":false},"*tp_rating_plans":{"remote":false,"replicate":false},"*tp_rating_profiles":{"remote":false,"replicate":false},"*tp_resources":{"remote":false,"replicate":false},"*tp_routes":{"remote":false,"replicate":false},"*tp_shared_groups":{"remote":false,"replicate":false},"*tp_stats":{"remote":false,"replicate":false},"*tp_thresholds":{"remote":false,"replicate":false},"*tp_timings":{"remote":false,"replicate":false},"*versions":{"remote":false,"replicate":false}},"opts":{"mongoQueryTimeout":"10s","mysqlLocation":"Local","postgresSSLMode":"disable","sqlConnMaxLifetime":0,"sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}`
cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSON)
if err != nil {
t.Fatal(err)
@@ -5355,19 +5357,20 @@ func TestCgrCdfEventExporter(t *testing.T) {
},
Exporters: []*EventExporterCfg{
{
- ID: utils.MetaDefault,
- Type: utils.MetaNone,
- ExportPath: "/var/spool/cgrates/ees",
- Attempts: 1,
- Timezone: utils.EmptyString,
- Filters: []string{},
- AttributeSIDs: []string{},
- Flags: utils.FlagsWithParams{},
- Fields: []*FCTemplate{},
- contentFields: []*FCTemplate{},
- headerFields: []*FCTemplate{},
- trailerFields: []*FCTemplate{},
- Opts: make(map[string]interface{}),
+ ID: utils.MetaDefault,
+ Type: utils.MetaNone,
+ ExportPath: "/var/spool/cgrates/ees",
+ Attempts: 1,
+ Timezone: utils.EmptyString,
+ Filters: []string{},
+ AttributeSIDs: []string{},
+ Flags: utils.FlagsWithParams{},
+ Fields: []*FCTemplate{},
+ contentFields: []*FCTemplate{},
+ headerFields: []*FCTemplate{},
+ trailerFields: []*FCTemplate{},
+ Opts: make(map[string]interface{}),
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
},
},
}
@@ -5435,19 +5438,20 @@ func TestCgrCfgEventReaderDefault(t *testing.T) {
func TestCgrCfgEventExporterDefault(t *testing.T) {
eCfg := &EventExporterCfg{
- ID: utils.MetaDefault,
- Type: utils.MetaNone,
- ExportPath: "/var/spool/cgrates/ees",
- Attempts: 1,
- Timezone: utils.EmptyString,
- Filters: []string{},
- AttributeSIDs: []string{},
- Flags: utils.FlagsWithParams{},
- contentFields: []*FCTemplate{},
- Fields: []*FCTemplate{},
- headerFields: []*FCTemplate{},
- trailerFields: []*FCTemplate{},
- Opts: make(map[string]interface{}),
+ ID: utils.MetaDefault,
+ Type: utils.MetaNone,
+ ExportPath: "/var/spool/cgrates/ees",
+ Attempts: 1,
+ Timezone: utils.EmptyString,
+ Filters: []string{},
+ AttributeSIDs: []string{},
+ Flags: utils.FlagsWithParams{},
+ contentFields: []*FCTemplate{},
+ Fields: []*FCTemplate{},
+ headerFields: []*FCTemplate{},
+ trailerFields: []*FCTemplate{},
+ Opts: make(map[string]interface{}),
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
}
if !reflect.DeepEqual(cgrCfg.dfltEvExp, eCfg) {
t.Errorf("received: %+v,\n expecting: %+v", utils.ToJSON(cgrCfg.dfltEvExp), utils.ToJSON(eCfg))
diff --git a/config/eescfg_test.go b/config/eescfg_test.go
index a098b836c..18e08e437 100644
--- a/config/eescfg_test.go
+++ b/config/eescfg_test.go
@@ -74,32 +74,34 @@ func TestEESClone(t *testing.T) {
},
Exporters: []*EventExporterCfg{
{
- ID: utils.MetaDefault,
- Type: utils.MetaNone,
- Synchronous: false,
- ExportPath: "/var/spool/cgrates/ees",
- Attempts: 1,
- Timezone: utils.EmptyString,
- AttributeSCtx: utils.EmptyString,
- Filters: []string{},
- AttributeSIDs: []string{},
- Flags: utils.FlagsWithParams{},
- Fields: []*FCTemplate{},
- contentFields: []*FCTemplate{},
- headerFields: []*FCTemplate{},
- trailerFields: []*FCTemplate{},
- Opts: make(map[string]interface{}),
+ ID: utils.MetaDefault,
+ Type: utils.MetaNone,
+ Synchronous: false,
+ ExportPath: "/var/spool/cgrates/ees",
+ Attempts: 1,
+ Timezone: utils.EmptyString,
+ AttributeSCtx: utils.EmptyString,
+ Filters: []string{},
+ AttributeSIDs: []string{},
+ Flags: utils.FlagsWithParams{},
+ Fields: []*FCTemplate{},
+ contentFields: []*FCTemplate{},
+ headerFields: []*FCTemplate{},
+ trailerFields: []*FCTemplate{},
+ Opts: make(map[string]interface{}),
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
},
{
- ID: utils.CGRateSLwr,
- Type: utils.MetaNone,
- Synchronous: false,
- ExportPath: "/var/spool/cgrates/ees",
- Attempts: 2,
- Timezone: "local",
- Filters: []string{"randomFiletrs"},
- AttributeSIDs: []string{"randomID"},
- Flags: utils.FlagsWithParams{},
+ ID: utils.CGRateSLwr,
+ Type: utils.MetaNone,
+ Synchronous: false,
+ ExportPath: "/var/spool/cgrates/ees",
+ Attempts: 2,
+ Timezone: "local",
+ Filters: []string{"randomFiletrs"},
+ AttributeSIDs: []string{"randomID"},
+ Flags: utils.FlagsWithParams{},
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
Fields: []*FCTemplate{
{
Tag: utils.CGRID,
@@ -269,19 +271,20 @@ func TestEventExporterSameID(t *testing.T) {
},
Exporters: []*EventExporterCfg{
{
- ID: utils.MetaDefault,
- Type: utils.MetaNone,
- ExportPath: "/var/spool/cgrates/ees",
- Attempts: 1,
- Timezone: utils.EmptyString,
- Filters: []string{},
- AttributeSIDs: []string{},
- Flags: utils.FlagsWithParams{},
- Fields: []*FCTemplate{},
- contentFields: []*FCTemplate{},
- headerFields: []*FCTemplate{},
- trailerFields: []*FCTemplate{},
- Opts: make(map[string]interface{}),
+ ID: utils.MetaDefault,
+ Type: utils.MetaNone,
+ ExportPath: "/var/spool/cgrates/ees",
+ Attempts: 1,
+ Timezone: utils.EmptyString,
+ Filters: []string{},
+ AttributeSIDs: []string{},
+ Flags: utils.FlagsWithParams{},
+ Fields: []*FCTemplate{},
+ contentFields: []*FCTemplate{},
+ headerFields: []*FCTemplate{},
+ trailerFields: []*FCTemplate{},
+ Opts: make(map[string]interface{}),
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
},
{
ID: "file_exporter1",
@@ -300,9 +303,10 @@ func TestEventExporterSameID(t *testing.T) {
{Tag: "CustomTag2", Path: "*exp.CustomPath2", Type: utils.MetaVariable,
Value: NewRSRParsersMustCompile("CustomValue2", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339},
},
- headerFields: []*FCTemplate{},
- trailerFields: []*FCTemplate{},
- Opts: make(map[string]interface{}),
+ headerFields: []*FCTemplate{},
+ trailerFields: []*FCTemplate{},
+ Opts: make(map[string]interface{}),
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
},
},
}
@@ -356,15 +360,16 @@ func TestEEsCfgloadFromJsonCfgCase1(t *testing.T) {
},
Exporters: &[]*EventExporterJsonCfg{
{
- Id: utils.StringPointer("CSVExporter"),
- Type: utils.StringPointer("*file_csv"),
- Filters: &[]string{},
- Attribute_ids: &[]string{},
- Flags: &[]string{"*dryrun"},
- Export_path: utils.StringPointer("/tmp/testCSV"),
- Timezone: utils.StringPointer("UTC"),
- Synchronous: utils.BoolPointer(true),
- Attempts: utils.IntPointer(1),
+ Id: utils.StringPointer("CSVExporter"),
+ Type: utils.StringPointer("*file_csv"),
+ Filters: &[]string{},
+ Attribute_ids: &[]string{},
+ Flags: &[]string{"*dryrun"},
+ Export_path: utils.StringPointer("/tmp/testCSV"),
+ Timezone: utils.StringPointer("UTC"),
+ Synchronous: utils.BoolPointer(true),
+ Attempts: utils.IntPointer(1),
+ Failed_posts_dir: utils.StringPointer("/var/spool/cgrates/failed_posts"),
Fields: &[]*FcTemplateJsonCfg{
{
Tag: utils.StringPointer(utils.CGRID),
@@ -388,19 +393,20 @@ func TestEEsCfgloadFromJsonCfgCase1(t *testing.T) {
},
Exporters: []*EventExporterCfg{
{
- ID: utils.MetaDefault,
- Type: utils.MetaNone,
- ExportPath: "/var/spool/cgrates/ees",
- Attempts: 1,
- Timezone: utils.EmptyString,
- Filters: []string{},
- AttributeSIDs: []string{},
- Flags: utils.FlagsWithParams{},
- contentFields: []*FCTemplate{},
- Fields: []*FCTemplate{},
- headerFields: []*FCTemplate{},
- trailerFields: []*FCTemplate{},
- Opts: make(map[string]interface{}),
+ ID: utils.MetaDefault,
+ Type: utils.MetaNone,
+ ExportPath: "/var/spool/cgrates/ees",
+ Attempts: 1,
+ Timezone: utils.EmptyString,
+ Filters: []string{},
+ AttributeSIDs: []string{},
+ Flags: utils.FlagsWithParams{},
+ contentFields: []*FCTemplate{},
+ Fields: []*FCTemplate{},
+ headerFields: []*FCTemplate{},
+ trailerFields: []*FCTemplate{},
+ Opts: make(map[string]interface{}),
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
},
{
ID: "CSVExporter",
@@ -427,6 +433,7 @@ func TestEEsCfgloadFromJsonCfgCase1(t *testing.T) {
Fields: []*FCTemplate{
{Tag: utils.CGRID, Path: "*exp.CGRID", Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.CGRID", utils.InfieldSep), Layout: time.RFC3339},
},
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
},
},
}
@@ -499,19 +506,20 @@ func TestEEsCfgloadFromJsonCfgCase2(t *testing.T) {
},
Exporters: []*EventExporterCfg{
{
- ID: utils.MetaDefault,
- Type: utils.MetaNone,
- ExportPath: "/var/spool/cgrates/ees",
- Attempts: 1,
- Timezone: utils.EmptyString,
- Filters: []string{},
- AttributeSIDs: []string{},
- Flags: utils.FlagsWithParams{},
- contentFields: []*FCTemplate{},
- Fields: []*FCTemplate{},
- headerFields: []*FCTemplate{},
- trailerFields: []*FCTemplate{},
- Opts: make(map[string]interface{}),
+ ID: utils.MetaDefault,
+ Type: utils.MetaNone,
+ ExportPath: "/var/spool/cgrates/ees",
+ Attempts: 1,
+ Timezone: utils.EmptyString,
+ Filters: []string{},
+ AttributeSIDs: []string{},
+ Flags: utils.FlagsWithParams{},
+ contentFields: []*FCTemplate{},
+ Fields: []*FCTemplate{},
+ headerFields: []*FCTemplate{},
+ trailerFields: []*FCTemplate{},
+ Opts: make(map[string]interface{}),
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
},
{
ID: "CSVExporter",
@@ -534,7 +542,8 @@ func TestEEsCfgloadFromJsonCfgCase2(t *testing.T) {
Layout: time.RFC3339,
},
},
- Opts: make(map[string]interface{}),
+ FailedPostsDir: "/var/spool/cgrates/failed_posts",
+ Opts: make(map[string]interface{}),
Fields: []*FCTemplate{
{
Tag: utils.CGRID,
@@ -650,6 +659,7 @@ func TestEEsCfgAsMapInterface(t *testing.T) {
utils.ValueCfg: "~*req.CGRID",
},
},
+ utils.FailedPostsDirCfg: "/var/spool/cgrates/failed_posts",
},
},
}
diff --git a/cores/server.go b/cores/server.go
index 8ee8d2119..d214e3286 100644
--- a/cores/server.go
+++ b/cores/server.go
@@ -35,11 +35,10 @@ import (
"sync"
"time"
+ "github.com/cenkalti/rpc2"
"github.com/cgrates/cgrates/analyzers"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
-
- "github.com/cenkalti/rpc2"
"golang.org/x/net/websocket"
)
diff --git a/cores/server_it_test.go b/cores/server_it_test.go
index a1e6c08c4..218f5179d 100644
--- a/cores/server_it_test.go
+++ b/cores/server_it_test.go
@@ -38,17 +38,12 @@ import (
"testing"
"time"
- "golang.org/x/net/websocket"
-
- sessions2 "github.com/cgrates/cgrates/sessions"
-
"github.com/cenkalti/rpc2"
-
"github.com/cgrates/cgrates/config"
-
"github.com/cgrates/cgrates/engine"
-
+ "github.com/cgrates/cgrates/sessions"
"github.com/cgrates/cgrates/utils"
+ "golang.org/x/net/websocket"
)
var (
@@ -333,10 +328,10 @@ func testServeBiJSON(t *testing.T) {
data := engine.NewInternalDB(nil, nil, true)
dm := engine.NewDataManager(data, cfgDflt.CacheCfg(), nil)
- sessions := sessions2.NewSessionS(cfgDflt, dm, nil)
+ ss := sessions.NewSessionS(cfgDflt, dm, nil)
go func() {
- if err := server.ServeBiRPC(":3434", "", sessions.OnBiJSONConnect, sessions.OnBiJSONDisconnect); err != nil {
+ if err := server.ServeBiRPC(":3434", "", ss.OnBiJSONConnect, ss.OnBiJSONDisconnect); err != nil {
t.Error(err)
}
}()
@@ -352,11 +347,11 @@ func testServeBiJSONEmptyBiRPCServer(t *testing.T) {
data := engine.NewInternalDB(nil, nil, true)
dm := engine.NewDataManager(data, cfgDflt.CacheCfg(), nil)
- sessions := sessions2.NewSessionS(cfgDflt, dm, nil)
+ ss := sessions.NewSessionS(cfgDflt, dm, nil)
expectedErr := "BiRPCServer should not be nil"
go func() {
- if err := server.ServeBiRPC(":3430", "", sessions.OnBiJSONConnect, sessions.OnBiJSONDisconnect); err == nil || err.Error() != "BiRPCServer should not be nil" {
+ if err := server.ServeBiRPC(":3430", "", ss.OnBiJSONConnect, ss.OnBiJSONDisconnect); err == nil || err.Error() != "BiRPCServer should not be nil" {
t.Errorf("Expected %+v, received %+v", expectedErr, err)
}
}()
@@ -374,11 +369,11 @@ func testServeBiJSONInvalidPort(t *testing.T) {
data := engine.NewInternalDB(nil, nil, true)
dm := engine.NewDataManager(data, cfgDflt.CacheCfg(), nil)
- sessions := sessions2.NewSessionS(cfgDflt, dm, nil)
+ ss := sessions.NewSessionS(cfgDflt, dm, nil)
expectedErr := "listen tcp: address invalid_port_format: missing port in address"
- if err := server.ServeBiRPC("invalid_port_format", "", sessions.OnBiJSONConnect,
- sessions.OnBiJSONDisconnect); err == nil || err.Error() != expectedErr {
+ if err := server.ServeBiRPC("invalid_port_format", "", ss.OnBiJSONConnect,
+ ss.OnBiJSONDisconnect); err == nil || err.Error() != expectedErr {
t.Errorf("Expected %+v, received %+v", expectedErr, err)
}
@@ -395,11 +390,11 @@ func testServeBiGoB(t *testing.T) {
data := engine.NewInternalDB(nil, nil, true)
dm := engine.NewDataManager(data, cfgDflt.CacheCfg(), nil)
- sessions := sessions2.NewSessionS(cfgDflt, dm, nil)
+ ss := sessions.NewSessionS(cfgDflt, dm, nil)
go func() {
- if err := server.ServeBiRPC("", ":9343", sessions.OnBiJSONConnect, sessions.OnBiJSONDisconnect); err != nil {
- t.Error(err)
+ if err := server.ServeBiRPC("", ":9343", ss.OnBiJSONConnect, ss.OnBiJSONDisconnect); err != nil {
+ t.Log(err)
}
}()
runtime.Gosched()
@@ -414,11 +409,11 @@ func testServeBiGoBEmptyBiRPCServer(t *testing.T) {
data := engine.NewInternalDB(nil, nil, true)
dm := engine.NewDataManager(data, cfgDflt.CacheCfg(), nil)
- sessions := sessions2.NewSessionS(cfgDflt, dm, nil)
+ ss := sessions.NewSessionS(cfgDflt, dm, nil)
expectedErr := "BiRPCServer should not be nil"
go func() {
- if err := server.ServeBiRPC("", ":93430", sessions.OnBiJSONConnect, sessions.OnBiJSONDisconnect); err == nil || err.Error() != "BiRPCServer should not be nil" {
+ if err := server.ServeBiRPC("", ":93430", ss.OnBiJSONConnect, ss.OnBiJSONDisconnect); err == nil || err.Error() != "BiRPCServer should not be nil" {
t.Errorf("Expected %+v, received %+v", expectedErr, err)
}
}()
@@ -436,11 +431,11 @@ func testServeBiGoBInvalidPort(t *testing.T) {
data := engine.NewInternalDB(nil, nil, true)
dm := engine.NewDataManager(data, cfgDflt.CacheCfg(), nil)
- sessions := sessions2.NewSessionS(cfgDflt, dm, nil)
+ ss := sessions.NewSessionS(cfgDflt, dm, nil)
expectedErr := "listen tcp: address invalid_port_format: missing port in address"
- if err := server.ServeBiRPC("", "invalid_port_format", sessions.OnBiJSONConnect,
- sessions.OnBiJSONDisconnect); err == nil || err.Error() != expectedErr {
+ if err := server.ServeBiRPC("", "invalid_port_format", ss.OnBiJSONConnect,
+ ss.OnBiJSONDisconnect); err == nil || err.Error() != expectedErr {
t.Errorf("Expected %+v, received %+v", expectedErr, err)
}
diff --git a/cores/server_test.go b/cores/server_test.go
index fdca3b089..72afd1539 100644
--- a/cores/server_test.go
+++ b/cores/server_test.go
@@ -28,7 +28,6 @@ import (
"github.com/cgrates/cgrates/agents"
"github.com/cgrates/cgrates/analyzers"
-
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
diff --git a/dispatchers/dispatchers_it_test.go b/dispatchers/dispatchers_it_test.go
index ba442a7dd..fe94cbf54 100644
--- a/dispatchers/dispatchers_it_test.go
+++ b/dispatchers/dispatchers_it_test.go
@@ -138,7 +138,7 @@ func testDspApierUnkownAPiKey(t *testing.T) {
}
}
- */
+*/
func TestDispatcherServiceDispatcherProfileForEventGetDispatchertWithoutAuthentification(t *testing.T) {
cfg := config.NewDefaultCGRConfig()
diff --git a/ees/amqpv1.go b/ees/amqpv1.go
new file mode 100644
index 000000000..150b2cbdf
--- /dev/null
+++ b/ees/amqpv1.go
@@ -0,0 +1,115 @@
+/*
+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 ees
+
+import (
+ "context"
+ "sync"
+
+ amqpv1 "github.com/Azure/go-amqp"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/utils"
+)
+
+// NewAMQPv1EE creates a poster for amqpv1
+func NewAMQPv1EE(cfg *config.EventExporterCfg, dc *utils.SafeMapStorage) *AMQPv1EE {
+ pstr := &AMQPv1EE{
+ cfg: cfg,
+ dc: dc,
+ queueID: "/" + utils.DefaultQueueID,
+ reqs: newConcReq(cfg.ConcurrentRequests),
+ }
+ if vals, has := cfg.Opts[utils.AMQPQueueID]; has {
+ pstr.queueID = "/" + utils.IfaceAsString(vals)
+ }
+ return pstr
+}
+
+// AMQPv1EE a poster for amqpv1
+type AMQPv1EE struct {
+ queueID string // identifier of the CDR queue where we publish
+ client *amqpv1.Client
+ session *amqpv1.Session
+
+ cfg *config.EventExporterCfg
+ dc *utils.SafeMapStorage
+ reqs *concReq
+ sync.RWMutex // protect connection
+ bytePreparing
+}
+
+func (pstr *AMQPv1EE) Cfg() *config.EventExporterCfg { return pstr.cfg }
+
+func (pstr *AMQPv1EE) Connect() (err error) {
+ pstr.Lock()
+ defer pstr.Unlock()
+ if pstr.client == nil {
+ if pstr.client, err = amqpv1.Dial(pstr.Cfg().ExportPath); err != nil {
+ return
+ }
+ }
+ if pstr.session == nil {
+ pstr.session, err = pstr.client.NewSession()
+ if err != nil {
+ // reset client and try again
+ // used in case of closed connection because of idle time
+ if pstr.client != nil {
+ pstr.client.Close() // Make shure the connection is closed before reseting it
+ pstr.client = nil
+ }
+ }
+ }
+ return
+}
+
+func (pstr *AMQPv1EE) ExportEvent(content interface{}, _ string) (err error) {
+ pstr.reqs.get()
+ pstr.RLock()
+ defer func() {
+ pstr.RUnlock()
+ pstr.reqs.done()
+ }()
+ sender, err := pstr.session.NewSender(
+ amqpv1.LinkTargetAddress(pstr.queueID),
+ )
+ if err != nil {
+ return
+ }
+ // Send message
+ ctx := context.Background()
+ err = sender.Send(ctx, amqpv1.NewMessage(content.([]byte)))
+ sender.Close(ctx)
+ return
+}
+
+func (pstr *AMQPv1EE) Close() (err error) {
+ pstr.Lock()
+ if pstr.session != nil {
+ pstr.session.Close(context.Background())
+ pstr.session = nil
+ }
+ if pstr.client != nil {
+ err = pstr.client.Close()
+ pstr.client = nil
+ }
+ pstr.Unlock()
+ return
+}
+
+func (pstr *AMQPv1EE) GetMetrics() *utils.SafeMapStorage { return pstr.dc }
diff --git a/ees/ee.go b/ees/ee.go
index bbb445707..ae08f4e47 100644
--- a/ees/ee.go
+++ b/ees/ee.go
@@ -29,7 +29,7 @@ import (
"github.com/cgrates/cgrates/utils"
)
-type EventExporter2 interface {
+type EventExporter interface {
Cfg() *config.EventExporterCfg // return the config
Connect() error // called before exporting an event to make sure it is connected
ExportEvent(interface{}, string) error // called on each event to be exported
@@ -40,15 +40,14 @@ type EventExporter2 interface {
}
// NewEventExporter produces exporters
-func NewEventExporter(cgrCfg *config.CGRConfig, cfgIdx int, filterS *engine.FilterS) (ee EventExporter2, err error) {
+func NewEventExporter(cfg *config.EventExporterCfg, cgrCfg *config.CGRConfig, filterS *engine.FilterS) (ee EventExporter, err error) {
var dc *utils.SafeMapStorage
if dc, err = newEEMetrics(utils.FirstNonEmpty(
- cgrCfg.EEsCfg().Exporters[cfgIdx].Timezone,
+ cfg.Timezone,
cgrCfg.GeneralCfg().DefaultTimezone)); err != nil {
return
}
- cfg := cgrCfg.EEsCfg().Exporters[cfgIdx]
- switch cgrCfg.EEsCfg().Exporters[cfgIdx].Type {
+ switch cfg.Type {
case utils.MetaFileCSV:
return NewFileCSVee(cfg, cgrCfg, filterS, dc)
case utils.MetaFileFWV:
@@ -62,10 +61,14 @@ func NewEventExporter(cgrCfg *config.CGRConfig, cfgIdx int, filterS *engine.Filt
cgrCfg.GeneralCfg().ConnectTimeout, dc)
case utils.MetaAMQPjsonMap:
return NewAMQPee(cfg, dc), nil
- case utils.MetaAMQPV1jsonMap,
- utils.MetaSQSjsonMap, utils.MetaKafkajsonMap,
- utils.MetaS3jsonMap:
- return NewPosterJSONMapEE(cgrCfg, cfgIdx, filterS, dc)
+ case utils.MetaAMQPV1jsonMap:
+ return NewAMQPv1EE(cfg, dc), nil
+ case utils.MetaS3jsonMap:
+ return NewS3EE(cfg, dc), nil
+ case utils.MetaSQSjsonMap:
+ return NewSQSee(cfg, dc), nil
+ case utils.MetaKafkajsonMap:
+ return NewKafkaEE(cfg, dc), nil
case utils.MetaVirt:
return NewVirtualEE(cfg, dc)
case utils.MetaElastic:
@@ -73,7 +76,7 @@ func NewEventExporter(cgrCfg *config.CGRConfig, cfgIdx int, filterS *engine.Filt
case utils.MetaSQL:
return NewSQLEe(cfg, dc)
default:
- return nil, fmt.Errorf("unsupported exporter type: <%s>", cgrCfg.EEsCfg().Exporters[cfgIdx].Type)
+ return nil, fmt.Errorf("unsupported exporter type: <%s>", cfg.Type)
}
}
@@ -222,10 +225,10 @@ func updateEEMetrics(dc *utils.SafeMapStorage, cgrID string, ev engine.MapEvent,
type bytePreparing struct{}
-func (eEe *bytePreparing) PrepareMap(mp map[string]interface{}) (interface{}, error) {
+func (bytePreparing) PrepareMap(mp map[string]interface{}) (interface{}, error) {
return json.Marshal(mp)
}
-func (eEe *bytePreparing) PrepareOrderMap(mp *utils.OrderedNavigableMap) (interface{}, error) {
+func (bytePreparing) PrepareOrderMap(mp *utils.OrderedNavigableMap) (interface{}, error) {
valMp := make(map[string]interface{})
for el := mp.GetFirstElement(); el != nil; el = el.Next() {
path := el.Value
@@ -238,13 +241,13 @@ func (eEe *bytePreparing) PrepareOrderMap(mp *utils.OrderedNavigableMap) (interf
type slicePreparing struct{}
-func (eEe *slicePreparing) PrepareMap(mp map[string]interface{}) (interface{}, error) {
+func (slicePreparing) PrepareMap(mp map[string]interface{}) (interface{}, error) {
csvRecord := make([]string, 0, len(mp))
for _, val := range mp {
csvRecord = append(csvRecord, utils.IfaceAsString(val))
}
return csvRecord, nil
}
-func (eEe *slicePreparing) PrepareOrderMap(mp *utils.OrderedNavigableMap) (interface{}, error) {
+func (slicePreparing) PrepareOrderMap(mp *utils.OrderedNavigableMap) (interface{}, error) {
return mp.OrderedFieldsAsStrings(), nil
}
diff --git a/ees/ee_test.go b/ees/ee_test.go
index e1e1f8af1..4be09996d 100644
--- a/ees/ee_test.go
+++ b/ees/ee_test.go
@@ -33,7 +33,7 @@ func TestNewEventExporter(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaFileCSV
cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 0
filterS := engine.NewFilterS(cgrCfg, nil, nil)
- ee, err := NewEventExporter(cgrCfg, 0, filterS)
+ ee, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS)
errExpect := "open /var/spool/cgrates/ees/*default_"
if strings.Contains(errExpect, err.Error()) {
t.Errorf("Expected %+v but got %+v", errExpect, err)
@@ -45,7 +45,7 @@ func TestNewEventExporter(t *testing.T) {
if err != nil {
t.Error(err)
}
- eeExpect, err := NewFileCSVee(cgrCfg, 0, filterS, dc)
+ eeExpect, err := NewFileCSVee(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS, dc)
if strings.Contains(errExpect, err.Error()) {
t.Errorf("Expected %+v but got %+v", errExpect, err)
}
@@ -66,7 +66,7 @@ func TestNewEventExporterCase2(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaFileFWV
cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 0
filterS := engine.NewFilterS(cgrCfg, nil, nil)
- ee, err := NewEventExporter(cgrCfg, 0, filterS)
+ ee, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS)
errExpect := "open /var/spool/cgrates/ees/*default_"
if strings.Contains(errExpect, err.Error()) {
t.Errorf("Expected %+v but got %+v", errExpect, err)
@@ -76,7 +76,7 @@ func TestNewEventExporterCase2(t *testing.T) {
"Local",
utils.EmptyString,
))
- eeExpect, err := NewFileFWVee(cgrCfg, 0, filterS, dc)
+ eeExpect, err := NewFileFWVee(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS, dc)
if strings.Contains(errExpect, err.Error()) {
t.Errorf("Expected %+v but got %+v", errExpect, err)
}
@@ -96,7 +96,7 @@ func TestNewEventExporterCase3(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPPost
cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 0
filterS := engine.NewFilterS(cgrCfg, nil, nil)
- ee, err := NewEventExporter(cgrCfg, 0, filterS)
+ ee, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS)
if err != nil {
t.Error(err)
}
@@ -104,7 +104,7 @@ func TestNewEventExporterCase3(t *testing.T) {
"Local",
utils.EmptyString,
))
- eeExpect, err := NewHTTPPostEE(cgrCfg, 0, filterS, dc)
+ eeExpect, err := NewHTTPPostEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS, dc)
if err != nil {
t.Error(err)
}
@@ -121,7 +121,7 @@ func TestNewEventExporterCase4(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPjsonMap
cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 0
filterS := engine.NewFilterS(cgrCfg, nil, nil)
- ee, err := NewEventExporter(cgrCfg, 0, filterS)
+ ee, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS)
if err != nil {
t.Error(err)
}
@@ -129,7 +129,7 @@ func TestNewEventExporterCase4(t *testing.T) {
"Local",
utils.EmptyString,
))
- eeExpect, err := NewHTTPjsonMapEE(cgrCfg, 0, filterS, dc)
+ eeExpect, err := NewHTTPjsonMapEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS, dc)
if err != nil {
t.Error(err)
}
@@ -141,37 +141,12 @@ func TestNewEventExporterCase4(t *testing.T) {
}
}
-func TestNewEventExporterCase5(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaAMQPjsonMap
- cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 0
- filterS := engine.NewFilterS(cgrCfg, nil, nil)
- ee, err := NewEventExporter(cgrCfg, 0, filterS)
- if err != nil {
- t.Error(err)
- }
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- eeExpect, err := NewPosterJSONMapEE(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- newEE := ee.(*PosterJSONMapEE)
- newEE.dc.MapStorage[utils.TimeNow] = nil
- eeExpect.dc.MapStorage[utils.TimeNow] = nil
- if !reflect.DeepEqual(eeExpect, newEE) {
- t.Errorf("Expected %+v \n but got %+v", utils.ToJSON(eeExpect), utils.ToJSON(newEE))
- }
-}
-
func TestNewEventExporterCase6(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaVirt
cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 0
filterS := engine.NewFilterS(cgrCfg, nil, nil)
- ee, err := NewEventExporter(cgrCfg, 0, filterS)
+ ee, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS)
if err != nil {
t.Error(err)
}
@@ -182,7 +157,7 @@ func TestNewEventExporterCase6(t *testing.T) {
if err != nil {
t.Error(err)
}
- eeExpect, err := NewVirtualEE(cgrCfg, 0, filterS, dc)
+ eeExpect, err := NewVirtualEE(cgrCfg.EEsCfg().Exporters[0], dc)
if err != nil {
t.Error(err)
}
@@ -199,7 +174,7 @@ func TestNewEventExporterDefaultCase(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaNone
cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 0
filterS := engine.NewFilterS(cgrCfg, nil, nil)
- _, err := NewEventExporter(cgrCfg, 0, filterS)
+ _, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS)
errExpect := fmt.Sprintf("unsupported exporter type: <%s>", utils.MetaNone)
if err.Error() != errExpect {
t.Errorf("Expected %+v \n but got %+v", errExpect, err)
@@ -213,7 +188,7 @@ func TestNewEventExporterCase7(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 0
cgrCfg.EEsCfg().Exporters[0].ExportPath = "/invalid/path"
filterS := engine.NewFilterS(cgrCfg, nil, nil)
- ee, err := NewEventExporter(cgrCfg, 0, filterS)
+ ee, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS)
if err != nil {
t.Error(err)
}
@@ -224,7 +199,7 @@ func TestNewEventExporterCase7(t *testing.T) {
if err != nil {
t.Error(err)
}
- eeExpect, err := NewElasticEE(cgrCfg, 0, filterS, dc)
+ eeExpect, err := NewElasticEE(cgrCfg.EEsCfg().Exporters[0], dc)
if err != nil {
t.Error(err)
}
@@ -243,7 +218,7 @@ func TestNewEventExporterCase8(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaSQL
cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 0
filterS := engine.NewFilterS(cgrCfg, nil, nil)
- _, err := NewEventExporter(cgrCfg, 0, filterS)
+ _, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS)
errExpect := "MANDATORY_IE_MISSING: [sqlTableName]"
if err == nil || err.Error() != errExpect {
t.Errorf("Expected %+v \n but got %+v", errExpect, err)
@@ -254,7 +229,7 @@ func TestNewEventExporterCase8(t *testing.T) {
func TestNewEventExporterDcCase(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
cgrCfg.GeneralCfg().DefaultTimezone = "invalid_timezone"
- _, err := NewEventExporter(cgrCfg, 0, nil)
+ _, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil)
errExpect := "unknown time zone invalid_timezone"
if err == nil || err.Error() != errExpect {
t.Errorf("Expected %+v \n but got %+v", errExpect, err)
diff --git a/ees/ees.go b/ees/ees.go
index 413c2b7ef..bb3b64bb6 100644
--- a/ees/ees.go
+++ b/ees/ees.go
@@ -31,7 +31,7 @@ import (
// onCacheEvicted is called by ltcache when evicting an item
func onCacheEvicted(_ string, value interface{}) {
- ee := value.(EventExporter2)
+ ee := value.(EventExporter)
ee.Close()
}
@@ -183,16 +183,16 @@ func (eeS *EventExporterS) V1ProcessEvent(cgrEv *utils.CGREventWithEeIDs, rply *
eeCache, hasCache := eeS.eesChs[eeCfg.Type]
eeS.eesMux.RUnlock()
var isCached bool
- var ee EventExporter2
+ var ee EventExporter
if hasCache {
var x interface{}
if x, isCached = eeCache.Get(eeCfg.ID); isCached {
- ee = x.(EventExporter2)
+ ee = x.(EventExporter)
}
}
if !isCached {
- if ee, err = NewEventExporter(eeS.cfg, cfgIdx, eeS.filterS); err != nil {
+ if ee, err = NewEventExporter(eeS.cfg.EEsCfg().Exporters[cfgIdx], eeS.cfg, eeS.filterS); err != nil {
return
}
if hasCache {
@@ -214,9 +214,8 @@ func (eeS *EventExporterS) V1ProcessEvent(cgrEv *utils.CGREventWithEeIDs, rply *
fmt.Sprintf("<%s> with id <%s>, running verbosed exporter with syncronous false",
utils.EEs, ee.Cfg().ID))
}
- go func(evict, sync bool, ee EventExporter2) {
- if err := eeS.exportEventWithExporter(ee, cgrEv.CGREvent, evict); err != nil {
-
+ go func(evict, sync bool, ee EventExporter) {
+ if err := exportEventWithExporter(ee, cgrEv.CGREvent, evict, eeS.cfg, eeS.filterS); err != nil {
withErr = true
}
if sync {
@@ -260,7 +259,7 @@ func (eeS *EventExporterS) V1ProcessEvent(cgrEv *utils.CGREventWithEeIDs, rply *
return
}
-func (eeS *EventExporterS) exportEventWithExporter(exp EventExporter2, ev *utils.CGREvent, oneTime bool) (err error) {
+func exportEventWithExporter(exp EventExporter, ev *utils.CGREvent, oneTime bool, cfg *config.CGRConfig, filterS *engine.FilterS) (err error) {
if oneTime {
defer exp.Close()
}
@@ -279,9 +278,9 @@ func (eeS *EventExporterS) exportEventWithExporter(exp EventExporter2, ev *utils
utils.MetaReq: utils.MapStorage(ev.Event),
utils.MetaDC: exp.GetMetrics(),
utils.MetaOpts: utils.MapStorage(ev.APIOpts),
- utils.MetaCfg: eeS.cfg.GetDataProvider(),
- }, utils.FirstNonEmpty(ev.Tenant, eeS.cfg.GeneralCfg().DefaultTenant),
- eeS.filterS,
+ utils.MetaCfg: cfg.GetDataProvider(),
+ }, utils.FirstNonEmpty(ev.Tenant, cfg.GeneralCfg().DefaultTenant),
+ filterS,
map[string]*utils.OrderedNavigableMap{utils.MetaExp: expNM}).SetFields(exp.Cfg().ContentFields())
if eEv, err = exp.PrepareOrderMap(expNM); err != nil {
return
@@ -293,11 +292,11 @@ func (eeS *EventExporterS) exportEventWithExporter(exp EventExporter2, ev *utils
return ExportWithAttempts(exp, eEv, key)
}
-func ExportWithAttempts(exp EventExporter2, eEv interface{}, key string) (err error) {
+func ExportWithAttempts(exp EventExporter, eEv interface{}, key string) (err error) {
if exp.Cfg().FailedPostsDir != utils.MetaNone {
defer func() {
if err != nil {
- engine.AddFailedPost(exp.Cfg().FailedPostsDir, exp.Cfg().ExportPath,
+ AddFailedPost(exp.Cfg().FailedPostsDir, exp.Cfg().ExportPath,
exp.Cfg().Type, utils.EEs,
eEv, exp.Cfg().Opts)
}
diff --git a/ees/ees_test.go b/ees/ees_test.go
index 6982ee296..0f81fa158 100644
--- a/ees/ees_test.go
+++ b/ees/ees_test.go
@@ -66,7 +66,7 @@ func TestListenAndServe(t *testing.T) {
logBuf := new(bytes.Buffer)
log.SetOutput(logBuf)
eeS.ListenAndServe(stopChan, cfgRld)
- logExpect := "[INFO] starting "
+ logExpect := "[INFO] starting "
if rcv := logBuf.String(); !strings.Contains(rcv, logExpect) {
t.Errorf("Expected %q but received %q", logExpect, rcv)
}
@@ -292,7 +292,7 @@ func TestV1ProcessEvent4(t *testing.T) {
utils.MetaHTTPPost: ltcache.NewCache(1,
time.Second, false, onCacheEvicted),
}
- newEeS, err := NewEventExporter(cgrCfg, 0, filterS)
+ newEeS, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS)
if err != nil {
t.Error(err)
}
@@ -318,23 +318,34 @@ func TestV1ProcessEvent4(t *testing.T) {
}
}
-type mockEventExporter struct{}
-
-func (mockEventExporter) ID() string { return utils.EmptyString }
-func (mockEventExporter) ExportEvent(cgrEv *utils.CGREvent) error { return nil }
-func (mockEventExporter) OnEvicted(itdmID string, value interface{}) {
- utils.Logger.Warning("NOT IMPLEMENTED")
+func newMockEventExporter() *mockEventExporter {
+ return &mockEventExporter{dc: &utils.SafeMapStorage{
+ MapStorage: utils.MapStorage{
+ utils.NumberOfEvents: int64(0),
+ utils.PositiveExports: utils.StringSet{},
+ utils.NegativeExports: 5,
+ }}}
}
-func (mockEventExporter) GetMetrics() *utils.SafeMapStorage {
- return &utils.SafeMapStorage{MapStorage: utils.MapStorage{
- utils.NumberOfEvents: int64(0),
- utils.PositiveExports: utils.StringSet{},
- utils.NegativeExports: 5,
- }}
+
+type mockEventExporter struct {
+ dc *utils.SafeMapStorage
+ bytePreparing
+}
+
+func (m mockEventExporter) GetMetrics() *utils.SafeMapStorage {
+ return m.dc
+}
+
+func (mockEventExporter) Cfg() *config.EventExporterCfg { return new(config.EventExporterCfg) }
+func (mockEventExporter) Connect() error { return nil }
+func (mockEventExporter) ExportEvent(interface{}, string) error { return nil }
+func (mockEventExporter) Close() error {
+ utils.Logger.Warning("NOT IMPLEMENTED")
+ return nil
}
func TestV1ProcessEventMockMetrics(t *testing.T) {
- mEe := mockEventExporter{}
+ mEe := newMockEventExporter()
cgrCfg := config.NewDefaultCGRConfig()
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPPost
cgrCfg.EEsCfg().Exporters[0].ID = "SQLExporterFull"
@@ -435,7 +446,7 @@ func TestOnCacheEvicted(t *testing.T) {
utils.Logger.SetLogLevel(7)
bufLog := new(bytes.Buffer)
log.SetOutput(bufLog)
- ee := mockEventExporter{}
+ ee := newMockEventExporter()
onCacheEvicted(utils.EmptyString, ee)
rcvExpect := "CGRateS <> [WARNING] NOT IMPLEMENTED"
if rcv := bufLog.String(); !strings.Contains(rcv, rcvExpect) {
@@ -452,7 +463,7 @@ func TestShutdown(t *testing.T) {
logBuf := new(bytes.Buffer)
log.SetOutput(logBuf)
eeS.Shutdown()
- logExpect := "[INFO] shutdown "
+ logExpect := "[INFO] shutdown "
if rcv := logBuf.String(); !strings.Contains(rcv, logExpect) {
t.Errorf("Expected %q but received %q", logExpect, rcv)
}
diff --git a/ees/elastic_test.go b/ees/elastic_test.go
index ed1a52c95..308f4a20a 100644
--- a/ees/elastic_test.go
+++ b/ees/elastic_test.go
@@ -25,24 +25,11 @@ import (
"testing"
"github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
-func TestID(t *testing.T) {
- ee := &ElasticEE{
- id: "3",
- }
- if rcv := ee.ID(); !reflect.DeepEqual(rcv, "3") {
- t.Errorf("Expected %+v \n but got %+v", "3", rcv)
- }
-}
-
func TestGetMetrics(t *testing.T) {
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
@@ -56,23 +43,23 @@ func TestGetMetrics(t *testing.T) {
}
func TestInitClient(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ ExportPath: "/\x00",
+ },
}
- ee.cgrCfg.EEsCfg().Exporters[0].ExportPath = "/\x00"
errExpect := `cannot create client: parse "/\x00": net/url: invalid control character in URL`
- if err := ee.init(); err == nil || err.Error() != errExpect {
+ if err := ee.Connect(); err == nil || err.Error() != errExpect {
t.Errorf("Expected %+v \n but got %+v", errExpect, err)
}
}
func TestInitCase1(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsIndex] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsIndex: "test"},
+ },
}
- if err := ee.init(); err != nil {
+ if err := ee.prepareOpts(); err != nil {
t.Error(err)
}
eeExpect := "test"
@@ -82,12 +69,12 @@ func TestInitCase1(t *testing.T) {
}
func TestInitCase2(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsIfPrimaryTerm] = 20
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsIfPrimaryTerm: 20},
+ },
}
- if err := ee.init(); err != nil {
+ if err := ee.prepareOpts(); err != nil {
t.Error(err)
}
eeExpect := utils.IntPointer(20)
@@ -97,24 +84,24 @@ func TestInitCase2(t *testing.T) {
}
func TestInitCase2Err(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsIfPrimaryTerm] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsIfPrimaryTerm: "test"},
+ },
}
errExpect := "strconv.ParseInt: parsing \"test\": invalid syntax"
- if err := ee.init(); err == nil || err.Error() != errExpect {
+ if err := ee.prepareOpts(); err == nil || err.Error() != errExpect {
t.Errorf("Expected %+v \n but got %+v", errExpect, err)
}
}
func TestInitCase3(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsIfSeqNo] = 20
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsIfSeqNo: 20},
+ },
}
- if err := ee.init(); err != nil {
+ if err := ee.prepareOpts(); err != nil {
t.Error(err)
}
eeExpect := utils.IntPointer(20)
@@ -124,24 +111,24 @@ func TestInitCase3(t *testing.T) {
}
func TestInitCase3Err(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsIfSeqNo] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsIfSeqNo: "test"},
+ },
}
errExpect := "strconv.ParseInt: parsing \"test\": invalid syntax"
- if err := ee.init(); err == nil || err.Error() != errExpect {
+ if err := ee.prepareOpts(); err == nil || err.Error() != errExpect {
t.Errorf("Expected %+v \n but got %+v", errExpect, err)
}
}
func TestInitCase4(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsOpType] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsOpType: "test"},
+ },
}
- if err := ee.init(); err != nil {
+ if err := ee.prepareOpts(); err != nil {
t.Error(err)
}
eeExpect := "test"
@@ -151,12 +138,12 @@ func TestInitCase4(t *testing.T) {
}
func TestInitCase5(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsPipeline] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsPipeline: "test"},
+ },
}
- if err := ee.init(); err != nil {
+ if err := ee.prepareOpts(); err != nil {
t.Error(err)
}
eeExpect := "test"
@@ -166,12 +153,12 @@ func TestInitCase5(t *testing.T) {
}
func TestInitCase6(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsRouting] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsRouting: "test"},
+ },
}
- if err := ee.init(); err != nil {
+ if err := ee.prepareOpts(); err != nil {
t.Error(err)
}
eeExpect := "test"
@@ -181,24 +168,24 @@ func TestInitCase6(t *testing.T) {
}
func TestInitCase7(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsTimeout] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsTimeout: "test"},
+ },
}
errExpect := "time: invalid duration \"test\""
- if err := ee.init(); err == nil || err.Error() != errExpect {
+ if err := ee.prepareOpts(); err == nil || err.Error() != errExpect {
t.Errorf("Expected %+v \n but got %+v", errExpect, err)
}
}
func TestInitCase8(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsVersionLow] = 20
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsVersionLow: 20},
+ },
}
- if err := ee.init(); err != nil {
+ if err := ee.prepareOpts(); err != nil {
t.Error(err)
}
eeExpect := utils.IntPointer(20)
@@ -208,24 +195,24 @@ func TestInitCase8(t *testing.T) {
}
func TestInitCase8Err(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsVersionLow] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsVersionLow: "test"},
+ },
}
errExpect := "strconv.ParseInt: parsing \"test\": invalid syntax"
- if err := ee.init(); err == nil || err.Error() != errExpect {
+ if err := ee.prepareOpts(); err == nil || err.Error() != errExpect {
t.Errorf("Expected %+v \n but got %+v", errExpect, err)
}
}
func TestInitCase9(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsVersionType] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsVersionType: "test"},
+ },
}
- if err := ee.init(); err != nil {
+ if err := ee.prepareOpts(); err != nil {
t.Error(err)
}
eeExpect := "test"
@@ -235,12 +222,12 @@ func TestInitCase9(t *testing.T) {
}
func TestInitCase10(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.ElsWaitForActiveShards] = "test"
ee := &ElasticEE{
- cgrCfg: cgrCfg,
+ cfg: &config.EventExporterCfg{
+ Opts: map[string]interface{}{utils.ElsWaitForActiveShards: "test"},
+ },
}
- if err := ee.init(); err != nil {
+ if err := ee.prepareOpts(); err != nil {
t.Error(err)
}
eeExpect := "test"
@@ -262,40 +249,19 @@ func (mockClientErr) Perform(req *http.Request) (res *http.Response, err error)
func TestElasticExportEvent(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
- eEe, err := NewElasticEE(cgrCfg, 0, filterS, dc)
+ eEe, err := NewElasticEE(cgrCfg.EEsCfg().Exporters[0], dc)
if err != nil {
t.Error(err)
}
+ if err = eEe.Connect(); err != nil {
+ t.Error(err)
+ }
eEe.eClnt.Transport = new(mockClientErr)
- cgrEv.Event = map[string]interface{}{
- "test1": "value",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- if err := eEe.ExportEvent(cgrEv); err != nil {
+ if err := eEe.ExportEvent([]byte{}, ""); err != nil {
t.Error(err)
}
}
@@ -313,41 +279,21 @@ func (mockClientErr2) Perform(req *http.Request) (res *http.Response, err error)
func TestElasticExportEvent2(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
- eEe, err := NewElasticEE(cgrCfg, 0, filterS, dc)
+ eEe, err := NewElasticEE(cgrCfg.EEsCfg().Exporters[0], dc)
if err != nil {
t.Error(err)
}
+ if err = eEe.Connect(); err != nil {
+ t.Error(err)
+ }
eEe.eClnt.Transport = new(mockClientErr2)
- cgrEv.Event = map[string]interface{}{
- "test1": "value",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
+
errExpect := io.EOF
- if err := eEe.ExportEvent(cgrEv); err == nil || err != errExpect {
+ if err := eEe.ExportEvent([]byte{}, ""); err == nil || err != errExpect {
t.Errorf("Expected %v but received %v", errExpect, err)
}
}
@@ -364,125 +310,40 @@ func (mockClient) Perform(req *http.Request) (res *http.Response, err error) {
}
func TestElasticExportEvent3(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
- eEe, err := NewElasticEE(cgrCfg, 0, filterS, dc)
+ eEe, err := NewElasticEE(cgrCfg.EEsCfg().Exporters[0], dc)
if err != nil {
t.Error(err)
}
+ if err = eEe.Connect(); err != nil {
+ t.Error(err)
+ }
eEe.eClnt.Transport = new(mockClient)
- cgrEv.Event = map[string]interface{}{
- "test1": "value",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
// errExpect := `unsupported protocol scheme ""`
cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- if err := eEe.ExportEvent(cgrEv); err != nil {
+ if err := eEe.ExportEvent([]byte{}, ""); err != nil {
t.Error(err)
}
}
func TestElasticExportEvent4(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
- eEe, err := NewElasticEE(cgrCfg, 0, filterS, dc)
+ eEe, err := NewElasticEE(cgrCfg.EEsCfg().Exporters[0], dc)
if err != nil {
t.Error(err)
}
- // eEe.eClnt.Transport = new(mockClient)
- cgrEv.Event = map[string]interface{}{
- "test1": "value",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
+ if err = eEe.Connect(); err != nil {
+ t.Error(err)
}
errExpect := `unsupported protocol scheme ""`
- if err := eEe.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
+ if err := eEe.ExportEvent([]byte{}, ""); err == nil || err.Error() != errExpect {
t.Errorf("Expected %q but got %q", errExpect, err)
}
}
-
-func TestElasticExportEvent5(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
- eEe, err := NewElasticEE(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- // eEe.eClnt.Transport = new(mockClient)
- cgrEv.Event = map[string]interface{}{
- "test1": "value",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- errExpect := "inline parse error for string: <*wrong-type>"
- if err := eEe.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
- eEe.OnEvicted("test", "test")
-}
diff --git a/ees/filecsv_it_test.go b/ees/filecsv_it_test.go
index af79d34e4..9b97381ff 100644
--- a/ees/filecsv_it_test.go
+++ b/ees/filecsv_it_test.go
@@ -556,6 +556,7 @@ func TestCsvInitFileCSV(t *testing.T) {
}
fCsv := &FileCSVee{
cgrCfg: cgrCfg,
+ cfg: cgrCfg.EEsCfg().Exporters[0],
dc: dc,
}
if err := fCsv.init(); err != nil {
diff --git a/ees/filecsv_test.go b/ees/filecsv_test.go
index c69319b84..c1fe001e6 100644
--- a/ees/filecsv_test.go
+++ b/ees/filecsv_test.go
@@ -23,24 +23,13 @@ import (
"encoding/csv"
"io"
"reflect"
- "sync"
"testing"
- "time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
-func TestFileCsvID(t *testing.T) {
- fCsv := &FileCSVee{
- id: "3",
- }
- if rcv := fCsv.ID(); !reflect.DeepEqual(rcv, "3") {
- t.Errorf("Expected %+v \n but got %+v", "3", rcv)
- }
-}
-
func TestFileCsvGetMetrics(t *testing.T) {
dc, err := newEEMetrics(utils.FirstNonEmpty(
"Local",
@@ -49,9 +38,7 @@ func TestFileCsvGetMetrics(t *testing.T) {
if err != nil {
t.Error(err)
}
- fCsv := &FileCSVee{
- dc: dc,
- }
+ fCsv := &FileCSVee{dc: dc}
if rcv := fCsv.GetMetrics(); !reflect.DeepEqual(rcv, fCsv.dc) {
t.Errorf("Expected %+v \n but got %+v", utils.ToJSON(rcv), utils.ToJSON(fCsv.dc))
@@ -72,15 +59,14 @@ func TestFileCsvComposeHeader(t *testing.T) {
byteBuff := new(bytes.Buffer)
csvNW := csv.NewWriter(byteBuff)
fCsv := &FileCSVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloser{byteBuff},
csvWriter: csvNW,
dc: &utils.SafeMapStorage{},
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields = []*config.FCTemplate{
+ fCsv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*hdr.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -90,13 +76,13 @@ func TestFileCsvComposeHeader(t *testing.T) {
Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields {
+ for _, field := range fCsv.Cfg().Fields {
field.ComputePath()
}
if err := fCsv.composeHeader(); err != nil {
t.Error(err)
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].ComputeFields()
+ fCsv.Cfg().ComputeFields()
if err := fCsv.composeHeader(); err != nil {
t.Error(err)
}
@@ -105,7 +91,7 @@ func TestFileCsvComposeHeader(t *testing.T) {
if expected != byteBuff.String() {
t.Errorf("Expected %q but received %q", expected, byteBuff.String())
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields = []*config.FCTemplate{
+ fCsv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*hdr.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -117,10 +103,10 @@ func TestFileCsvComposeHeader(t *testing.T) {
Filters: []string{"*wrong-type"},
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields {
+ for _, field := range fCsv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].ComputeFields()
+ fCsv.Cfg().ComputeFields()
byteBuff.Reset()
errExpect := "inline parse error for string: <*wrong-type>"
if err := fCsv.composeHeader(); err == nil || err.Error() != errExpect {
@@ -136,15 +122,14 @@ func TestFileCsvComposeTrailer(t *testing.T) {
byteBuff := new(bytes.Buffer)
csvNW := csv.NewWriter(byteBuff)
fCsv := &FileCSVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloser{byteBuff},
csvWriter: csvNW,
dc: &utils.SafeMapStorage{},
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields = []*config.FCTemplate{
+ fCsv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*trl.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -154,13 +139,13 @@ func TestFileCsvComposeTrailer(t *testing.T) {
Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields {
+ for _, field := range fCsv.Cfg().Fields {
field.ComputePath()
}
if err := fCsv.composeTrailer(); err != nil {
t.Error(err)
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].ComputeFields()
+ fCsv.Cfg().ComputeFields()
if err := fCsv.composeTrailer(); err != nil {
t.Error(err)
}
@@ -169,7 +154,7 @@ func TestFileCsvComposeTrailer(t *testing.T) {
if expected != byteBuff.String() {
t.Errorf("Expected %q but received %q", expected, byteBuff.String())
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields = []*config.FCTemplate{
+ fCsv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*trl.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -181,10 +166,10 @@ func TestFileCsvComposeTrailer(t *testing.T) {
Filters: []string{"*wrong-type"},
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields {
+ for _, field := range fCsv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].ComputeFields()
+ fCsv.Cfg().ComputeFields()
byteBuff.Reset()
errExpect := "inline parse error for string: <*wrong-type>"
if err := fCsv.composeTrailer(); err == nil || err.Error() != errExpect {
@@ -194,7 +179,6 @@ func TestFileCsvComposeTrailer(t *testing.T) {
func TestFileCsvExportEvent(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
- cgrEv := new(utils.CGREvent)
newIDb := engine.NewInternalDB(nil, nil, true)
newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
filterS := engine.NewFilterS(cgrCfg, nil, newDM)
@@ -208,70 +192,21 @@ func TestFileCsvExportEvent(t *testing.T) {
t.Error(err)
}
fCsv := &FileCSVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloser{byteBuff},
csvWriter: csvNW,
dc: dc,
- reqs: newConcReq(0),
- }
- cgrEv.Event = map[string]interface{}{
- "test1": "value",
- }
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.test1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("3", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields {
- field.ComputePath()
- }
- if err := fCsv.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- csvNW.Flush()
- expected := "value\n"
- if expected != byteBuff.String() {
- t.Errorf("Expected %q but received %q", expected, byteBuff.String())
- }
- byteBuff.Reset()
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].ComputeFields()
- if err := fCsv.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- csvNW.Flush()
- expected = "value,3\n"
- if expected != byteBuff.String() {
- t.Errorf("Expected %q but received %q", expected, byteBuff.String())
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
+ if err := fCsv.ExportEvent([]string{"value", "3"}, ""); err != nil {
+ t.Error(err)
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].ComputeFields()
- byteBuff.Reset()
- errExpect := "inline parse error for string: <*wrong-type>"
- if err := fCsv.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
+ csvNW.Flush()
+ expected := "value,3\n"
+ if expected != byteBuff.String() {
+ t.Errorf("Expected %q but received %q", expected, byteBuff.String())
}
}
@@ -283,15 +218,14 @@ func TestFileCsvOnEvictedTrailer(t *testing.T) {
byteBuff := new(bytes.Buffer)
csvNW := csv.NewWriter(byteBuff)
fCsv := &FileCSVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloserWrite{byteBuff},
csvWriter: csvNW,
dc: &utils.SafeMapStorage{},
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields = []*config.FCTemplate{
+ fCsv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*trl.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -303,11 +237,11 @@ func TestFileCsvOnEvictedTrailer(t *testing.T) {
Filters: []string{"*wrong-type"},
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields {
+ for _, field := range fCsv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].ComputeFields()
- fCsv.OnEvicted("test", "test")
+ fCsv.Cfg().ComputeFields()
+ fCsv.Close()
}
func TestFileCsvOnEvictedClose(t *testing.T) {
@@ -318,15 +252,14 @@ func TestFileCsvOnEvictedClose(t *testing.T) {
byteBuff := new(bytes.Buffer)
csvNW := csv.NewWriter(byteBuff)
fCsv := &FileCSVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloserError{byteBuff},
csvWriter: csvNW,
dc: &utils.SafeMapStorage{},
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields = []*config.FCTemplate{
+ fCsv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*trl.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -336,81 +269,9 @@ func TestFileCsvOnEvictedClose(t *testing.T) {
Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].Fields {
+ for _, field := range fCsv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fCsv.cfgIdx].ComputeFields()
- fCsv.OnEvicted("test", "test")
-}
-
-type mockCsv struct {
- wg *sync.WaitGroup
-}
-
-func (mc *mockCsv) Close() error { return nil }
-func (mc *mockCsv) Write(s []byte) (n int, err error) {
- time.Sleep(25 * time.Millisecond)
- mc.wg.Done()
- return 0, nil
-}
-
-func TestFileCSVSync(t *testing.T) {
- //Create new exporter
- cgrCfg := config.NewDefaultCGRConfig()
- var cfgIdx int
- cfgIdx = 0
-
- cgrCfg.EEsCfg().Exporters[cfgIdx].Type = utils.MetaFileCSV
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- cgrCfg.EEsCfg().Exporters[cfgIdx].Timezone,
- cgrCfg.GeneralCfg().DefaultTimezone))
- if err != nil {
- t.Error(err)
- }
-
- //Create an event
- cgrEvent := &utils.CGREvent{
- Tenant: "cgrates.org",
- Event: map[string]interface{}{
- "Account": "1001",
- "Destination": "1002",
- },
- }
-
- var wg1 = &sync.WaitGroup{}
-
- wg1.Add(3)
-
- test := make(chan struct{})
- go func() {
- wg1.Wait()
- close(test)
- }()
- mckCsv := &mockCsv{
- wg: wg1,
- }
- exp := &FileCSVee{
- id: cgrCfg.EEsCfg().Exporters[cfgIdx].ID,
- cgrCfg: cgrCfg,
- cfgIdx: cfgIdx,
- filterS: new(engine.FilterS),
- file: mckCsv,
- csvWriter: csv.NewWriter(mckCsv),
- dc: dc,
- reqs: newConcReq(cgrCfg.EEsCfg().Exporters[cfgIdx].ConcurrentRequests),
- }
-
- for i := 0; i < 3; i++ {
- go func() {
- exp.ExportEvent(cgrEvent)
- exp.csvWriter.Flush()
- }()
- }
-
- select {
- case <-test:
- return
- case <-time.After(50 * time.Millisecond):
- t.Error("Can't asynchronously export events")
- }
+ fCsv.Cfg().ComputeFields()
+ fCsv.Close()
}
diff --git a/ees/filefwv_it_test.go b/ees/filefwv_it_test.go
index eed8e37a0..b092d50e6 100644
--- a/ees/filefwv_it_test.go
+++ b/ees/filefwv_it_test.go
@@ -170,6 +170,7 @@ func TestFileFwvInit(t *testing.T) {
}
fFwv := &FileFWVee{
cgrCfg: cgrCfg,
+ cfg: cgrCfg.EEsCfg().Exporters[0],
dc: dc,
}
if err := fFwv.init(); err != nil {
diff --git a/ees/filefwv_test.go b/ees/filefwv_test.go
index 321eb300d..294101f92 100644
--- a/ees/filefwv_test.go
+++ b/ees/filefwv_test.go
@@ -30,41 +30,18 @@ import (
"github.com/cgrates/cgrates/utils"
)
-func TestFileFwvID(t *testing.T) {
- fFwv := &FileFWVee{
- id: "3",
- }
- if rcv := fFwv.ID(); !reflect.DeepEqual(rcv, "3") {
- t.Errorf("Expected %+v but got %+v", "3", rcv)
- }
-}
-
func TestFileFwvGetMetrics(t *testing.T) {
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
- fFwv := &FileFWVee{
- dc: dc,
- }
+ fFwv := &FileFWVee{dc: dc}
if rcv := fFwv.GetMetrics(); !reflect.DeepEqual(rcv, fFwv.dc) {
t.Errorf("Expected %+v \n but got %+v", utils.ToJSON(rcv), utils.ToJSON(fFwv.dc))
}
}
-// type MyError struct{}
-
-// func (m *MyError) Error() string {
-// return "ERR"
-// }
-
-// func (nopCloser) WriteString(w io.Writer, s string) error {
-// return &MyError{}
-// }
func TestFileFwvComposeHeader(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
newIDb := engine.NewInternalDB(nil, nil, true)
@@ -73,14 +50,13 @@ func TestFileFwvComposeHeader(t *testing.T) {
byteBuff := new(bytes.Buffer)
csvNW := csv.NewWriter(byteBuff)
fFwv := &FileFWVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloser{byteBuff},
dc: &utils.SafeMapStorage{},
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
+ fFwv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*hdr.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -90,13 +66,13 @@ func TestFileFwvComposeHeader(t *testing.T) {
Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
+ for _, field := range fFwv.Cfg().Fields {
field.ComputePath()
}
if err := fFwv.composeHeader(); err != nil {
t.Error(err)
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
+ fFwv.Cfg().ComputeFields()
if err := fFwv.composeHeader(); err != nil {
t.Error(err)
}
@@ -105,7 +81,7 @@ func TestFileFwvComposeHeader(t *testing.T) {
if expected != byteBuff.String() {
t.Errorf("Expected %q but received %q", expected, byteBuff.String())
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
+ fFwv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*hdr.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -117,10 +93,10 @@ func TestFileFwvComposeHeader(t *testing.T) {
Filters: []string{"*wrong-type"},
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
+ for _, field := range fFwv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
+ fFwv.Cfg().ComputeFields()
byteBuff.Reset()
errExpect := "inline parse error for string: <*wrong-type>"
if err := fFwv.composeHeader(); err == nil || err.Error() != errExpect {
@@ -136,14 +112,13 @@ func TestFileFwvComposeTrailer(t *testing.T) {
byteBuff := new(bytes.Buffer)
csvNW := csv.NewWriter(byteBuff)
fFwv := &FileFWVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloser{byteBuff},
dc: &utils.SafeMapStorage{},
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
+ fFwv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*trl.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -153,13 +128,13 @@ func TestFileFwvComposeTrailer(t *testing.T) {
Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
+ for _, field := range fFwv.Cfg().Fields {
field.ComputePath()
}
if err := fFwv.composeTrailer(); err != nil {
t.Error(err)
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
+ fFwv.Cfg().ComputeFields()
if err := fFwv.composeTrailer(); err != nil {
t.Error(err)
}
@@ -168,7 +143,7 @@ func TestFileFwvComposeTrailer(t *testing.T) {
if expected != byteBuff.String() {
t.Errorf("Expected %q but received %q", expected, byteBuff.String())
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
+ fFwv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*trl.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -180,10 +155,10 @@ func TestFileFwvComposeTrailer(t *testing.T) {
Filters: []string{"*wrong-type"},
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
+ for _, field := range fFwv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
+ fFwv.Cfg().ComputeFields()
byteBuff.Reset()
errExpect := "inline parse error for string: <*wrong-type>"
if err := fFwv.composeTrailer(); err == nil || err.Error() != errExpect {
@@ -193,83 +168,30 @@ func TestFileFwvComposeTrailer(t *testing.T) {
func TestFileFwvExportEvent(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
- cgrEv := new(utils.CGREvent)
newIDb := engine.NewInternalDB(nil, nil, true)
newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
filterS := engine.NewFilterS(cgrCfg, nil, newDM)
byteBuff := new(bytes.Buffer)
csvNW := csv.NewWriter(byteBuff)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
fFwv := &FileFWVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloser{byteBuff},
dc: dc,
- reqs: newConcReq(0),
}
- cgrEv.Event = map[string]interface{}{
- "test1": "value",
- }
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.test1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("3", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
- field.ComputePath()
- }
- if err := fFwv.ExportEvent(cgrEv); err != nil {
+ if err := fFwv.ExportEvent([]string{"value", "3"}, ""); err != nil {
t.Error(err)
}
csvNW.Flush()
- expected := "value\n"
+ expected := "value3\n"
if expected != byteBuff.String() {
t.Errorf("Expected %q but received %q", expected, byteBuff.String())
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
- byteBuff.Reset()
- if err := fFwv.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- csvNW.Flush()
- expected = "value3\n"
- if expected != byteBuff.String() {
- t.Errorf("Expected %q but received %q", expected, byteBuff.String())
- }
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
- byteBuff.Reset()
- errExpect := "inline parse error for string: <*wrong-type>"
- if err := fFwv.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
}
type nopCloserWrite struct {
@@ -283,36 +205,22 @@ func (nopCloserWrite) Write(s []byte) (n int, err error) {
func TestFileFwvExportEventWriteError(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
- cgrEv := new(utils.CGREvent)
newIDb := engine.NewInternalDB(nil, nil, true)
newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
filterS := engine.NewFilterS(cgrCfg, nil, newDM)
byteBuff := new(bytes.Buffer)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
fFwv := &FileFWVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloserWrite{byteBuff},
dc: dc,
- reqs: newConcReq(0),
}
- cgrEv.Event = map[string]interface{}{
- "test1": "value",
- }
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{{}}
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
- if err := fFwv.ExportEvent(cgrEv); err == nil || err != utils.ErrNotImplemented {
+ if err := fFwv.ExportEvent([]string{""}, ""); err == nil || err != utils.ErrNotImplemented {
t.Errorf("Expected %q but received %q", utils.ErrNotImplemented, err)
}
}
@@ -324,15 +232,13 @@ func TestFileFwvComposeHeaderWriteError(t *testing.T) {
filterS := engine.NewFilterS(cgrCfg, nil, newDM)
byteBuff := new(bytes.Buffer)
fFwv := &FileFWVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloserWrite{byteBuff},
dc: &utils.SafeMapStorage{},
- reqs: newConcReq(0),
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
+ fFwv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*hdr.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -342,10 +248,10 @@ func TestFileFwvComposeHeaderWriteError(t *testing.T) {
Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
+ for _, field := range fFwv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
+ fFwv.Cfg().ComputeFields()
if err := fFwv.composeHeader(); err == nil || err != utils.ErrNotImplemented {
t.Errorf("Expected %q but received %q", utils.ErrNotImplemented, err)
}
@@ -358,15 +264,13 @@ func TestFileFwvComposeTrailerWriteError(t *testing.T) {
filterS := engine.NewFilterS(cgrCfg, nil, newDM)
byteBuff := new(bytes.Buffer)
fFwv := &FileFWVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloserWrite{byteBuff},
dc: &utils.SafeMapStorage{},
- reqs: newConcReq(0),
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
+ fFwv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*trl.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -376,10 +280,10 @@ func TestFileFwvComposeTrailerWriteError(t *testing.T) {
Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
+ for _, field := range fFwv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
+ fFwv.Cfg().ComputeFields()
if err := fFwv.composeTrailer(); err == nil || err != utils.ErrNotImplemented {
t.Errorf("Expected %q but received %q", utils.ErrNotImplemented, err)
}
@@ -391,15 +295,13 @@ func TestFileFwvOnEvictedTrailer(t *testing.T) {
filterS := engine.NewFilterS(cgrCfg, nil, newDM)
byteBuff := new(bytes.Buffer)
fFwv := &FileFWVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloserWrite{byteBuff},
dc: &utils.SafeMapStorage{},
- reqs: newConcReq(0),
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
+ fFwv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*trl.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -409,11 +311,11 @@ func TestFileFwvOnEvictedTrailer(t *testing.T) {
Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
+ for _, field := range fFwv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
- fFwv.OnEvicted("test", "test")
+ fFwv.Cfg().ComputeFields()
+ fFwv.Close()
}
type nopCloserError struct {
@@ -431,15 +333,13 @@ func TestFileFwvOnEvictedClose(t *testing.T) {
filterS := engine.NewFilterS(cgrCfg, nil, newDM)
byteBuff := new(bytes.Buffer)
fFwv := &FileFWVee{
- id: "string",
+ cfg: cgrCfg.EEsCfg().Exporters[0],
cgrCfg: cgrCfg,
- cfgIdx: 0,
filterS: filterS,
file: nopCloserError{byteBuff},
dc: &utils.SafeMapStorage{},
- reqs: newConcReq(0),
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields = []*config.FCTemplate{
+ fFwv.Cfg().Fields = []*config.FCTemplate{
{
Path: "*trl.1", Type: utils.MetaVariable,
Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
@@ -449,9 +349,9 @@ func TestFileFwvOnEvictedClose(t *testing.T) {
Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
},
}
- for _, field := range cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].Fields {
+ for _, field := range fFwv.Cfg().Fields {
field.ComputePath()
}
- cgrCfg.EEsCfg().Exporters[fFwv.cfgIdx].ComputeFields()
- fFwv.OnEvicted("test", "test")
+ fFwv.Cfg().ComputeFields()
+ fFwv.Close()
}
diff --git a/ees/httpjsonmap.go b/ees/httpjsonmap.go
index 555a7b91c..ff82ee741 100644
--- a/ees/httpjsonmap.go
+++ b/ees/httpjsonmap.go
@@ -80,7 +80,7 @@ func (httpEE *HTTPjsonMapEE) Connect() (_ error) { return }
func (httpEE *HTTPjsonMapEE) ExportEvent(content interface{}, _ string) (err error) {
httpEE.reqs.get()
defer httpEE.reqs.done()
- pReq := content.(httpPosterRequest)
+ pReq := content.(*HTTPPosterRequest)
var req *http.Request
if req, err = prepareRequest(httpEE.Cfg().ExportPath, utils.ContentJSON, pReq.Body, pReq.Header); err != nil {
return
@@ -95,7 +95,7 @@ func (httpEE *HTTPjsonMapEE) GetMetrics() *utils.SafeMapStorage { return httpEE.
func (httpEE *HTTPjsonMapEE) PrepareMap(mp map[string]interface{}) (interface{}, error) {
body, err := json.Marshal(mp)
- return &httpPosterRequest{
+ return &HTTPPosterRequest{
Header: httpEE.hdr,
Body: body,
}, err
@@ -110,7 +110,7 @@ func (httpEE *HTTPjsonMapEE) PrepareOrderMap(mp *utils.OrderedNavigableMap) (int
valMp[strings.Join(path, utils.NestingSep)] = nmIt.String()
}
body, err := json.Marshal(valMp)
- return &httpPosterRequest{
+ return &HTTPPosterRequest{
Header: httpEE.hdr,
Body: body,
}, err
diff --git a/ees/httpjsonmap_test.go b/ees/httpjsonmap_test.go
index 08b1418a4..e32f71415 100644
--- a/ees/httpjsonmap_test.go
+++ b/ees/httpjsonmap_test.go
@@ -28,24 +28,11 @@ import (
"time"
"github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
-func TestHttpJsonMapID(t *testing.T) {
- httpEE := &HTTPjsonMapEE{
- id: "3",
- }
- if rcv := httpEE.ID(); !reflect.DeepEqual(rcv, "3") {
- t.Errorf("Expected %+v but got %+v", "3", rcv)
- }
-}
-
func TestHttpJsonMapGetMetrics(t *testing.T) {
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
@@ -61,49 +48,21 @@ func TestHttpJsonMapGetMetrics(t *testing.T) {
func TestHttpJsonMapExportEvent1(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaSQSjsonMap
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
- httpEE, err := NewHTTPjsonMapEE(cgrCfg, 0, filterS, dc)
+ httpEE, err := NewHTTPjsonMapEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil, nil)
if err != nil {
t.Error(err)
}
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
errExpect := `Post "/var/spool/cgrates/ees": unsupported protocol scheme ""`
- if err := httpEE.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
+ if err := httpEE.ExportEvent(&HTTPPosterRequest{Body: []byte{}, Header: make(http.Header)}, ""); err == nil || err.Error() != errExpect {
t.Errorf("Expected %q but received %q", errExpect, err)
}
- dcExpect := int64(1)
- if !reflect.DeepEqual(dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents]) {
- t.Errorf("Expected %q but received %q", dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents])
- }
}
func TestHttpJsonMapExportEvent2(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaSQSjsonMap
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
+
bodyExpect := map[string]interface{}{
"2": "*req.field2",
}
@@ -120,258 +79,21 @@ func TestHttpJsonMapExportEvent2(t *testing.T) {
}))
defer srv.Close()
cgrCfg.EEsCfg().Exporters[0].ExportPath = srv.URL + "/"
- httpEE, err := NewHTTPjsonMapEE(cgrCfg, 0, filterS, dc)
+ httpEE, err := NewHTTPjsonMapEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil, nil)
if err != nil {
t.Error(err)
}
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- if err := httpEE.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- dcExpect := int64(1)
- if !reflect.DeepEqual(dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents]) {
- t.Errorf("Expected %q but received %q", dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents])
- }
-}
-func TestHttpJsonMapExportEvent3(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaSQSjsonMap
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- httpEE, err := NewHTTPjsonMapEE(cgrCfg, 0, filterS, dc)
- if err != nil {
+ if err := httpEE.ExportEvent(&HTTPPosterRequest{Body: []byte(`{"2": "*req.field2"}`), Header: make(http.Header)}, ""); err != nil {
t.Error(err)
}
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- errExpect := "inline parse error for string: <*wrong-type>"
- if err := httpEE.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
- dcExpect := int64(1)
- if !reflect.DeepEqual(dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents]) {
- t.Errorf("Expected %q but received %q", dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents])
- }
-}
-func TestHttpJsonMapExportEvent4(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaSQSjsonMap
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- httpEE, err := NewHTTPjsonMapEE(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field2", utils.InfieldSep),
- },
- {
- Path: "*hdr.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field2", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- errExpect := "inline parse error for string: <*wrong-type>"
- if err := httpEE.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
- dcExpect := int64(1)
- if !reflect.DeepEqual(dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents]) {
- t.Errorf("Expected %q but received %q", dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents])
- }
-}
-
-func TestHttpJsonMapExportEvent5(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaSQSjsonMap
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- httpEE, err := NewHTTPjsonMapEE(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- cgrEv.Event = map[string]interface{}{
- "test": make(chan int),
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{{}}
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- errExpect := "json: unsupported type: chan int"
- if err := httpEE.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
- dcExpect := int64(1)
- if !reflect.DeepEqual(dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents]) {
- t.Errorf("Expected %q but received %q", dcExpect, httpEE.dc.MapStorage[utils.NumberOfEvents])
- }
- httpEE.OnEvicted("test", "test")
-}
-
-func TestHttpJsonMapComposeHeader(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPjson
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
- httpEE, err := NewHTTPjsonMapEE(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*hdr.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
- },
- {
- Path: "*hdr.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- if _, err := httpEE.composeHeader(); err != nil {
- t.Error(err)
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- if _, err := httpEE.composeHeader(); err != nil {
- t.Error(err)
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*hdr.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- {
- Path: "*hdr.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- errExpect := "inline parse error for string: <*wrong-type>"
- if _, err := httpEE.composeHeader(); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
}
func TestHttpJsonMapSync(t *testing.T) {
//Create new exporter
cgrCfg := config.NewDefaultCGRConfig()
- var cfgIdx int
- cfgIdx = 0
+ cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPjsonMap
- cgrCfg.EEsCfg().Exporters[cfgIdx].Type = utils.MetaHTTPjsonMap
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- cgrCfg.EEsCfg().Exporters[cfgIdx].Timezone,
- cgrCfg.GeneralCfg().DefaultTimezone))
- if err != nil {
- t.Error(err)
- }
-
- //Create an event
- cgrEvent := &utils.CGREvent{
- Tenant: "cgrates.org",
- Event: map[string]interface{}{
- "Account": "1001",
- "Destination": "1002",
- },
- }
var wg1 sync.WaitGroup
wg1.Add(3)
@@ -383,22 +105,21 @@ func TestHttpJsonMapSync(t *testing.T) {
}()
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-
time.Sleep(25 * time.Millisecond)
wg1.Done()
}))
defer ts.Close()
- cgrCfg.EEsCfg().Exporters[cfgIdx].ExportPath = ts.URL
+ cgrCfg.EEsCfg().Exporters[0].ExportPath = ts.URL
- exp, err := NewHTTPjsonMapEE(cgrCfg, cfgIdx, new(engine.FilterS), dc)
+ exp, err := NewHTTPjsonMapEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil, nil)
if err != nil {
t.Error(err)
}
for i := 0; i < 3; i++ {
- go exp.ExportEvent(cgrEvent)
+ go exp.ExportEvent(&HTTPPosterRequest{Body: []byte(`{"2": "*req.field2"}`), Header: make(http.Header)}, "")
}
select {
@@ -412,28 +133,10 @@ func TestHttpJsonMapSync(t *testing.T) {
func TestHttpJsonMapSyncLimit(t *testing.T) {
//Create new exporter
cgrCfg := config.NewDefaultCGRConfig()
- var cfgIdx int
- cfgIdx = 0
+ cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPjsonMap
+ cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 1
- cgrCfg.EEsCfg().Exporters[cfgIdx].Type = utils.MetaHTTPjsonMap
- cgrCfg.EEsCfg().Exporters[cfgIdx].ConcurrentRequests = 1
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- cgrCfg.EEsCfg().Exporters[cfgIdx].Timezone,
- cgrCfg.GeneralCfg().DefaultTimezone))
- if err != nil {
- t.Error(err)
- }
-
- //Create an event
- cgrEvent := &utils.CGREvent{
- Tenant: "cgrates.org",
- Event: map[string]interface{}{
- "Account": "1001",
- "Destination": "1002",
- },
- }
var wg1 sync.WaitGroup
-
wg1.Add(3)
test := make(chan struct{})
@@ -449,15 +152,15 @@ func TestHttpJsonMapSyncLimit(t *testing.T) {
defer ts.Close()
- cgrCfg.EEsCfg().Exporters[cfgIdx].ExportPath = ts.URL
+ cgrCfg.EEsCfg().Exporters[0].ExportPath = ts.URL
- exp, err := NewHTTPjsonMapEE(cgrCfg, cfgIdx, new(engine.FilterS), dc)
+ exp, err := NewHTTPjsonMapEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil, nil)
if err != nil {
t.Error(err)
}
for i := 0; i < 3; i++ {
- go exp.ExportEvent(cgrEvent)
+ go exp.ExportEvent(&HTTPPosterRequest{Body: []byte(`{"2": "*req.field2"}`), Header: make(http.Header)}, "")
}
select {
diff --git a/ees/httppost.go b/ees/httppost.go
index 3b0369bc9..e116632dd 100644
--- a/ees/httppost.go
+++ b/ees/httppost.go
@@ -49,7 +49,7 @@ type HTTPPostEE struct {
hdr http.Header
}
-type httpPosterRequest struct {
+type HTTPPosterRequest struct {
Header http.Header
Body interface{}
}
@@ -80,7 +80,7 @@ func (httpPost *HTTPPostEE) Connect() (_ error) { return }
func (httpPost *HTTPPostEE) ExportEvent(content interface{}, _ string) (err error) {
httpPost.reqs.get()
defer httpPost.reqs.done()
- pReq := content.(*httpPosterRequest)
+ pReq := content.(*HTTPPosterRequest)
var req *http.Request
if req, err = prepareRequest(httpPost.Cfg().ExportPath, utils.ContentForm, pReq.Body, pReq.Header); err != nil {
return
@@ -98,7 +98,7 @@ func (httpPost *HTTPPostEE) PrepareMap(mp map[string]interface{}) (interface{},
for k, v := range mp {
urlVals.Set(k, utils.IfaceAsString(v))
}
- return &httpPosterRequest{
+ return &HTTPPosterRequest{
Header: httpPost.hdr,
Body: urlVals,
}, nil
@@ -112,7 +112,7 @@ func (httpPost *HTTPPostEE) PrepareOrderMap(mp *utils.OrderedNavigableMap) (inte
path = path[:len(path)-1] // remove the last index
urlVals.Set(strings.Join(path, utils.NestingSep), nmIt.String())
}
- return &httpPosterRequest{
+ return &HTTPPosterRequest{
Header: httpPost.hdr,
Body: urlVals,
}, nil
diff --git a/ees/httppost_test.go b/ees/httppost_test.go
index 2df819b68..919667ead 100644
--- a/ees/httppost_test.go
+++ b/ees/httppost_test.go
@@ -22,25 +22,16 @@ import (
"io"
"net/http"
"net/http/httptest"
+ "net/url"
"reflect"
"sync"
"testing"
"time"
"github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
-func TestHttpPostID(t *testing.T) {
- httpPost := &HTTPPostEE{
- id: "3",
- }
- if rcv := httpPost.ID(); !reflect.DeepEqual(rcv, "3") {
- t.Errorf("Expected %+v but got %+v", "3", rcv)
- }
-}
-
func TestHttpPostGetMetrics(t *testing.T) {
dc, err := newEEMetrics(utils.FirstNonEmpty(
"Local",
@@ -62,17 +53,7 @@ func TestHttpPostExportEvent(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPPost
cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
- httpPost, err := NewHTTPPostEE(cgrCfg, 0, filterS, dc)
+ httpPost, err := NewHTTPPostEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil, nil)
if err != nil {
t.Error(err)
}
@@ -80,29 +61,14 @@ func TestHttpPostExportEvent(t *testing.T) {
"Test1": 3,
}
errExpect := `Post "/var/spool/cgrates/ees": unsupported protocol scheme ""`
- if err := httpPost.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
+ if err := httpPost.ExportEvent(&HTTPPosterRequest{Body: url.Values{}, Header: make(http.Header)}, ""); err == nil || err.Error() != errExpect {
t.Errorf("Expected %q but received %q", errExpect, err)
}
- dcExpect := int64(1)
- if !reflect.DeepEqual(dcExpect, httpPost.dc.MapStorage[utils.NumberOfEvents]) {
- t.Errorf("Expected %q but received %q", dcExpect, httpPost.dc.MapStorage[utils.NumberOfEvents])
- }
}
func TestHttpPostExportEvent2(t *testing.T) {
cgrCfg := config.NewDefaultCGRConfig()
cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPPost
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
bodyExpect := "2=%2Areq.field2"
srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
@@ -117,215 +83,25 @@ func TestHttpPostExportEvent2(t *testing.T) {
}))
defer srv.Close()
cgrCfg.EEsCfg().Exporters[0].ExportPath = srv.URL + "/"
- httpPost, err := NewHTTPPostEE(cgrCfg, 0, filterS, dc)
+ httpPost, err := NewHTTPPostEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil, nil)
if err != nil {
t.Error(err)
}
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- if err := httpPost.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- dcExpect := int64(1)
- if !reflect.DeepEqual(dcExpect, httpPost.dc.MapStorage[utils.NumberOfEvents]) {
- t.Errorf("Expected %q but received %q", dcExpect, httpPost.dc.MapStorage[utils.NumberOfEvents])
- }
-}
-
-func TestHttpPostExportEvent3(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPPost
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ vals, err := httpPost.PrepareMap(map[string]interface{}{"2": "*req.field2"})
if err != nil {
+ t.Fatal(err)
+ }
+ if err := httpPost.ExportEvent(vals, ""); err != nil {
t.Error(err)
}
- httpPost, err := NewHTTPPostEE(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- cgrEv.Event = map[string]interface{}{
- "Test1": 3,
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- errExpect := "inline parse error for string: <*wrong-type>"
- if err := httpPost.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
- dcExpect := int64(1)
- if !reflect.DeepEqual(dcExpect, httpPost.dc.MapStorage[utils.NumberOfEvents]) {
- t.Errorf("Expected %q but received %q", dcExpect, httpPost.dc.MapStorage[utils.NumberOfEvents])
- }
-}
-
-func TestHttpPostExportEvent4(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPPost
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
- httpPost, err := NewHTTPPostEE(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- cgrEv.Event = map[string]interface{}{
- "Test1": 3,
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field2", utils.InfieldSep),
- },
- {
- Path: "*hdr.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field2", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- errExpect := "inline parse error for string: <*wrong-type>"
- if err := httpPost.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
- dcExpect := int64(1)
- if !reflect.DeepEqual(dcExpect, httpPost.dc.MapStorage[utils.NumberOfEvents]) {
- t.Errorf("Expected %q but received %q", dcExpect, httpPost.dc.MapStorage[utils.NumberOfEvents])
- }
- httpPost.OnEvicted("test", "test")
-}
-
-func TestHttpPostComposeHeader(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPPost
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
- httpPost, err := NewHTTPPostEE(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*hdr.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
- },
- {
- Path: "*hdr.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- if _, err := httpPost.composeHeader(); err != nil {
- t.Error(err)
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- if _, err := httpPost.composeHeader(); err != nil {
- t.Error(err)
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*hdr.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- {
- Path: "*hdr.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- errExpect := "inline parse error for string: <*wrong-type>"
- if _, err := httpPost.composeHeader(); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
}
func TestHttpPostSync(t *testing.T) {
//Create new exporter
cgrCfg := config.NewDefaultCGRConfig()
- var cfgIdx int
- cfgIdx = 0
- cgrCfg.EEsCfg().Exporters[cfgIdx].Type = utils.MetaHTTPPost
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- cgrCfg.EEsCfg().Exporters[cfgIdx].Timezone,
- cgrCfg.GeneralCfg().DefaultTimezone))
- if err != nil {
- t.Error(err)
- }
+ cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPPost
- //Create an event
- cgrEvent := &utils.CGREvent{
- Tenant: "cgrates.org",
- Event: map[string]interface{}{
- "Account": "1001",
- "Destination": "1002",
- },
- }
var wg1 sync.WaitGroup
wg1.Add(3)
@@ -343,15 +119,23 @@ func TestHttpPostSync(t *testing.T) {
defer ts.Close()
- cgrCfg.EEsCfg().Exporters[cfgIdx].ExportPath = ts.URL
+ cgrCfg.EEsCfg().Exporters[0].ExportPath = ts.URL
- exp, err := NewHTTPPostEE(cgrCfg, cfgIdx, new(engine.FilterS), dc)
+ exp, err := NewHTTPPostEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil, nil)
if err != nil {
t.Error(err)
}
+ vals, err := exp.PrepareMap(map[string]interface{}{
+ "Account": "1001",
+ "Destination": "1002",
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
for i := 0; i < 3; i++ {
- go exp.ExportEvent(cgrEvent)
+ go exp.ExportEvent(vals, "")
}
select {
@@ -365,28 +149,12 @@ func TestHttpPostSync(t *testing.T) {
func TestHttpPostSyncLimit(t *testing.T) {
//Create new exporter
cgrCfg := config.NewDefaultCGRConfig()
- var cfgIdx int
- cfgIdx = 0
- cgrCfg.EEsCfg().Exporters[cfgIdx].Type = utils.MetaHTTPPost
+ cgrCfg.EEsCfg().Exporters[0].Type = utils.MetaHTTPPost
// We set the limit of events to be exported lower than the amount of events we asynchronously want to export
- cgrCfg.EEsCfg().Exporters[cfgIdx].ConcurrentRequests = 1
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- cgrCfg.EEsCfg().Exporters[cfgIdx].Timezone,
- cgrCfg.GeneralCfg().DefaultTimezone))
- if err != nil {
- t.Error(err)
- }
+ cgrCfg.EEsCfg().Exporters[0].ConcurrentRequests = 1
- //Create an event
- cgrEvent := &utils.CGREvent{
- Tenant: "cgrates.org",
- Event: map[string]interface{}{
- "Account": "1001",
- "Destination": "1002",
- },
- }
var wg1 sync.WaitGroup
wg1.Add(3)
@@ -404,17 +172,24 @@ func TestHttpPostSyncLimit(t *testing.T) {
defer ts.Close()
- cgrCfg.EEsCfg().Exporters[cfgIdx].ExportPath = ts.URL
+ cgrCfg.EEsCfg().Exporters[0].ExportPath = ts.URL
- exp, err := NewHTTPPostEE(cgrCfg, cfgIdx, new(engine.FilterS), dc)
+ exp, err := NewHTTPPostEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil, nil)
if err != nil {
t.Error(err)
}
- for i := 0; i < 3; i++ {
- go exp.ExportEvent(cgrEvent)
+ vals, err := exp.PrepareMap(map[string]interface{}{
+ "Account": "1001",
+ "Destination": "1002",
+ })
+ if err != nil {
+ t.Fatal(err)
}
+ for i := 0; i < 3; i++ {
+ go exp.ExportEvent(vals, "")
+ }
select {
case <-test:
t.Error("Should not have been possible to asynchronously export events")
diff --git a/ees/kafka.go b/ees/kafka.go
new file mode 100644
index 000000000..523e0fb0a
--- /dev/null
+++ b/ees/kafka.go
@@ -0,0 +1,91 @@
+/*
+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 ees
+
+import (
+ "context"
+ "sync"
+
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/utils"
+ kafka "github.com/segmentio/kafka-go"
+)
+
+// NewKafkaEE creates a kafka poster
+func NewKafkaEE(cfg *config.EventExporterCfg, dc *utils.SafeMapStorage) *KafkaEE {
+ kfkPstr := &KafkaEE{
+ cfg: cfg,
+ dc: dc,
+ topic: utils.DefaultQueueID,
+ }
+ if vals, has := cfg.Opts[utils.KafkaTopic]; has {
+ kfkPstr.topic = utils.IfaceAsString(vals)
+ }
+ return kfkPstr
+}
+
+// KafkaEE is a kafka poster
+type KafkaEE struct {
+ topic string // identifier of the CDR queue where we publish
+ writer *kafka.Writer
+
+ cfg *config.EventExporterCfg
+ dc *utils.SafeMapStorage
+ reqs *concReq
+ sync.RWMutex // protect connection
+ bytePreparing
+}
+
+func (pstr *KafkaEE) Cfg() *config.EventExporterCfg { return pstr.cfg }
+
+func (pstr *KafkaEE) Connect() (_ error) {
+ pstr.Lock()
+ if pstr.writer == nil {
+ pstr.writer = kafka.NewWriter(kafka.WriterConfig{
+ Brokers: []string{pstr.Cfg().ExportPath},
+ MaxAttempts: pstr.Cfg().Attempts,
+ Topic: pstr.topic,
+ })
+ }
+ pstr.Unlock()
+ return
+}
+
+func (pstr *KafkaEE) ExportEvent(content interface{}, key string) (err error) {
+ pstr.reqs.get()
+ pstr.RLock()
+ err = pstr.writer.WriteMessages(context.Background(), kafka.Message{
+ Key: []byte(key),
+ Value: content.([]byte),
+ })
+ pstr.RUnlock()
+ pstr.reqs.done()
+ return
+}
+
+func (pstr *KafkaEE) Close() (err error) {
+ pstr.Lock()
+ if pstr.writer != nil {
+ err = pstr.writer.Close()
+ pstr.writer = nil
+ }
+ pstr.Unlock()
+ return
+}
+
+func (pstr *KafkaEE) GetMetrics() *utils.SafeMapStorage { return pstr.dc }
diff --git a/ees/libactions.go b/ees/libactions.go
new file mode 100644
index 000000000..8a3cfb348
--- /dev/null
+++ b/ees/libactions.go
@@ -0,0 +1,101 @@
+/*
+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 ees
+
+import (
+ "encoding/gob"
+ "encoding/json"
+ "net/http"
+
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+)
+
+func init() {
+ gob.Register(new(HTTPPosterRequest))
+ gob.Register(new(sqlPosterRequest))
+
+ engine.RegisterActionFunc(utils.MetaHTTPPost, callURL)
+ engine.RegisterActionFunc(utils.HttpPostAsync, callURLAsync)
+ engine.RegisterActionFunc(utils.MetaPostEvent, postEvent)
+}
+
+func getOneData(ub *engine.Account, extraData interface{}) ([]byte, error) {
+ switch {
+ case ub != nil:
+ return json.Marshal(ub)
+ case extraData != nil:
+ return json.Marshal(extraData)
+ }
+ return nil, nil
+}
+
+func callURL(ub *engine.Account, a *engine.Action, _ engine.Actions, extraData interface{}) error {
+ body, err := getOneData(ub, extraData)
+ if err != nil {
+ return err
+ }
+ pstr, err := NewHTTPjsonMapEE(&config.EventExporterCfg{
+ ID: a.Id,
+ ExportPath: a.ExtraParameters,
+ Attempts: config.CgrConfig().GeneralCfg().PosterAttempts,
+ FailedPostsDir: config.CgrConfig().GeneralCfg().FailedPostsDir,
+ }, config.CgrConfig(), nil, nil)
+ if err != nil {
+ return err
+ }
+ return ExportWithAttempts(pstr, &HTTPPosterRequest{Body: body, Header: make(http.Header)}, "")
+}
+
+// Does not block for posts, no error reports
+func callURLAsync(ub *engine.Account, a *engine.Action, _ engine.Actions, extraData interface{}) error {
+ body, err := getOneData(ub, extraData)
+ if err != nil {
+ return err
+ }
+ pstr, err := NewHTTPjsonMapEE(&config.EventExporterCfg{
+ ID: a.Id,
+ ExportPath: a.ExtraParameters,
+ Attempts: config.CgrConfig().GeneralCfg().PosterAttempts,
+ FailedPostsDir: config.CgrConfig().GeneralCfg().FailedPostsDir,
+ }, config.CgrConfig(), nil, nil)
+ if err != nil {
+ return err
+ }
+ go ExportWithAttempts(pstr, &HTTPPosterRequest{Body: body, Header: make(http.Header)}, "")
+ return nil
+}
+
+func postEvent(_ *engine.Account, a *engine.Action, _ engine.Actions, extraData interface{}) error {
+ body, err := json.Marshal(extraData)
+ if err != nil {
+ return err
+ }
+ pstr, err := NewHTTPjsonMapEE(&config.EventExporterCfg{
+ ID: a.Id,
+ ExportPath: a.ExtraParameters,
+ Attempts: config.CgrConfig().GeneralCfg().PosterAttempts,
+ FailedPostsDir: config.CgrConfig().GeneralCfg().FailedPostsDir,
+ }, config.CgrConfig(), nil, nil)
+ if err != nil {
+ return err
+ }
+ return ExportWithAttempts(pstr, &HTTPPosterRequest{Body: body, Header: make(http.Header)}, "")
+}
diff --git a/engine/libcdre.go b/ees/libcdre.go
similarity index 76%
rename from engine/libcdre.go
rename to ees/libcdre.go
index 008137763..d8372b743 100644
--- a/engine/libcdre.go
+++ b/ees/libcdre.go
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see
*/
-package engine
+package ees
import (
"bytes"
@@ -153,55 +153,28 @@ func (expEv *ExportEvents) ReplayFailedPosts(attempts int) (failedEvents *Export
Opts: expEv.Opts,
Format: expEv.Format,
}
- var pstr Poster
- keyFunc := func() string { return utils.EmptyString }
- switch expEv.Format {
- case utils.MetaHTTPjsonCDR, utils.MetaHTTPjsonMap, utils.MetaHTTPjson, utils.MetaHTTPPost:
- var pstr *HTTPPoster
- pstr, err = NewHTTPPoster(config.CgrConfig().GeneralCfg().ReplyTimeout, expEv.Path,
- utils.PosterTransportContentTypes[expEv.Format],
- config.CgrConfig().GeneralCfg().PosterAttempts)
- if err != nil {
- return expEv, err
- }
- for _, ev := range expEv.Events {
- req := ev.(*HTTPPosterRequest)
- err = pstr.PostValues(req.Body, req.Header)
- if err != nil {
- failedEvents.AddEvent(req)
- }
- }
- if len(failedEvents.Events) > 0 {
- err = utils.ErrPartiallyExecuted
- } else {
- failedEvents = nil
- }
+
+ var ee EventExporter
+ if ee, err = NewEventExporter(&config.EventExporterCfg{
+ ID: "ReplayFailedPosts",
+ Type: expEv.Format,
+ ExportPath: expEv.Path,
+ Opts: expEv.Opts,
+ Attempts: attempts,
+ FailedPostsDir: utils.MetaNone,
+ }, config.CgrConfig(), nil); err != nil {
return
- case utils.MetaAMQPjsonCDR, utils.MetaAMQPjsonMap:
- pstr = NewAMQPPoster(expEv.Path, attempts, expEv.Opts)
- case utils.MetaAMQPV1jsonMap:
- pstr = NewAMQPv1Poster(expEv.Path, attempts, expEv.Opts)
- case utils.MetaSQSjsonMap:
- pstr = NewSQSPoster(expEv.Path, attempts, expEv.Opts)
- case utils.MetaKafkajsonMap:
- pstr = NewKafkaPoster(expEv.Path, attempts, expEv.Opts)
+ }
+ keyFunc := func() string { return utils.EmptyString }
+ if expEv.Format == utils.MetaKafkajsonMap || expEv.Format == utils.MetaS3jsonMap {
keyFunc = utils.UUIDSha1Prefix
- case utils.MetaS3jsonMap:
- pstr = NewS3Poster(expEv.Path, attempts, expEv.Opts)
- keyFunc = utils.UUIDSha1Prefix
- case utils.MetaNatsjsonMap:
- if pstr, err = NewNatsPoster(expEv.Path, attempts, expEv.Opts,
- config.CgrConfig().GeneralCfg().NodeID,
- config.CgrConfig().GeneralCfg().ConnectTimeout); err != nil {
- return expEv, err
- }
}
for _, ev := range expEv.Events {
- if err = pstr.Post(ev.([]byte), keyFunc()); err != nil {
+ if err = ExportWithAttempts(ee, ev, keyFunc()); err != nil {
failedEvents.AddEvent(ev)
}
}
- pstr.Close()
+ ee.Close()
if len(failedEvents.Events) > 0 {
err = utils.ErrPartiallyExecuted
} else {
diff --git a/engine/z_libcdre_it_test.go b/ees/libcdre_it_test.go
similarity index 99%
rename from engine/z_libcdre_it_test.go
rename to ees/libcdre_it_test.go
index 634e59e72..4f7745353 100644
--- a/engine/z_libcdre_it_test.go
+++ b/ees/libcdre_it_test.go
@@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see
*/
-package engine
+package ees
import (
"os"
diff --git a/engine/libcdre_test.go b/ees/libcdre_test.go
similarity index 93%
rename from engine/libcdre_test.go
rename to ees/libcdre_test.go
index 8bd7f7137..dd9fa4d33 100644
--- a/engine/libcdre_test.go
+++ b/ees/libcdre_test.go
@@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see
*/
-package engine
+package ees
import (
"reflect"
@@ -38,7 +38,7 @@ func TestSetFldPostCacheTTL(t *testing.T) {
func TestAddFldPost(t *testing.T) {
SetFailedPostCacheTTL(5 * time.Second)
AddFailedPost("", "path1", "format1", "module1", "1", make(map[string]interface{}))
- x, ok := failedPostCache.Get(utils.ConcatenatedKey("path1", "format1", "module1"))
+ x, ok := failedPostCache.Get(utils.ConcatenatedKey("", "path1", "format1", "module1"))
if !ok {
t.Error("Error reading from cache")
}
@@ -62,7 +62,7 @@ func TestAddFldPost(t *testing.T) {
}
AddFailedPost("", "path1", "format1", "module1", "2", make(map[string]interface{}))
AddFailedPost("", "path2", "format2", "module2", "3", map[string]interface{}{utils.SQSQueueID: "qID"})
- x, ok = failedPostCache.Get(utils.ConcatenatedKey("path1", "format1", "module1"))
+ x, ok = failedPostCache.Get(utils.ConcatenatedKey("", "path1", "format1", "module1"))
if !ok {
t.Error("Error reading from cache")
}
@@ -83,7 +83,7 @@ func TestAddFldPost(t *testing.T) {
if !reflect.DeepEqual(eOut, failedPost) {
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eOut), utils.ToJSON(failedPost))
}
- x, ok = failedPostCache.Get(utils.ConcatenatedKey("path2", "format2", "module2", "qID"))
+ x, ok = failedPostCache.Get(utils.ConcatenatedKey("", "path2", "format2", "module2", "qID"))
if !ok {
t.Error("Error reading from cache")
}
diff --git a/ees/nats_it_test.go b/ees/nats_it_test.go
index f1a5287ce..808d6721b 100644
--- a/ees/nats_it_test.go
+++ b/ees/nats_it_test.go
@@ -38,23 +38,22 @@ func TestNatsEEJetStream(t *testing.T) {
}
time.Sleep(50 * time.Millisecond)
defer cmd.Process.Kill()
- cfgPath := path.Join(*dataDir, "conf", "samples", "ees")
- cfg, err := config.NewCGRConfigFromPath(cfgPath)
+ cgrCfg, err := config.NewCGRConfigFromPath(path.Join(*dataDir, "conf", "samples", "ees"))
if err != nil {
t.Fatal(err)
}
- var idx int
- for idx = range cfg.EEsCfg().Exporters {
- if cfg.EEsCfg().Exporters[idx].ID == "NatsJsonMapExporter" {
+ var cfg *config.EventExporterCfg
+ for _, cfg = range cgrCfg.EEsCfg().Exporters {
+ if cfg.ID == "NatsJsonMapExporter" {
break
}
}
- evExp, err := NewEventExporter(cfg, idx, new(engine.FilterS))
+ evExp, err := NewEventExporter(cfg, cgrCfg, nil)
if err != nil {
t.Fatal(err)
}
- nop, err := engine.GetNatsOpts(cfg.EEsCfg().Exporters[idx].Opts, "natsTest", time.Second)
+ nop, err := GetNatsOpts(cfg.Opts, "natsTest", time.Second)
if err != nil {
t.Fatal(err)
}
@@ -102,7 +101,7 @@ func TestNatsEEJetStream(t *testing.T) {
"Destination": "1002",
},
}
- if err := evExp.ExportEvent(cgrEv); err != nil {
+ if err := exportEventWithExporter(evExp, cgrEv, true, cgrCfg, new(engine.FilterS)); err != nil {
t.Fatal(err)
}
testCleanDirectory(t)
@@ -129,23 +128,22 @@ func TestNatsEE(t *testing.T) {
time.Sleep(50 * time.Millisecond)
defer cmd.Process.Kill()
- cfgPath := path.Join(*dataDir, "conf", "samples", "ees")
- cfg, err := config.NewCGRConfigFromPath(cfgPath)
+ cgrCfg, err := config.NewCGRConfigFromPath(path.Join(*dataDir, "conf", "samples", "ees"))
if err != nil {
t.Fatal(err)
}
- var idx int
- for idx = range cfg.EEsCfg().Exporters {
- if cfg.EEsCfg().Exporters[idx].ID == "NatsJsonMapExporter2" {
+ var cfg *config.EventExporterCfg
+ for _, cfg = range cgrCfg.EEsCfg().Exporters {
+ if cfg.ID == "NatsJsonMapExporter2" {
break
}
}
- evExp, err := NewEventExporter(cfg, idx, new(engine.FilterS))
+ evExp, err := NewEventExporter(cfg, cgrCfg, nil)
if err != nil {
t.Fatal(err)
}
- nop, err := engine.GetNatsOpts(cfg.EEsCfg().Exporters[idx].Opts, "natsTest", time.Second)
+ nop, err := GetNatsOpts(cfg.Opts, "natsTest", time.Second)
if err != nil {
t.Fatal(err)
}
@@ -169,7 +167,7 @@ func TestNatsEE(t *testing.T) {
"Destination": "1002",
},
}
- if err := evExp.ExportEvent(cgrEv); err != nil {
+ if err := exportEventWithExporter(evExp, cgrEv, true, cgrCfg, new(engine.FilterS)); err != nil {
t.Fatal(err)
}
testCleanDirectory(t)
diff --git a/engine/z_poster_it_test.go b/ees/poster_it_test.go
similarity index 84%
rename from engine/z_poster_it_test.go
rename to ees/poster_it_test.go
index 490ac1cca..dd4c10194 100644
--- a/engine/z_poster_it_test.go
+++ b/ees/poster_it_test.go
@@ -17,7 +17,7 @@ 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 engine
+package ees
import (
"context"
@@ -65,17 +65,20 @@ type TestContent struct {
func TestHttpJsonPoster(t *testing.T) {
SetFailedPostCacheTTL(time.Millisecond)
- config.CgrConfig().GeneralCfg().FailedPostsDir = "/tmp"
content := &TestContent{Var1: "Val1", Var2: "Val2"}
jsn, _ := json.Marshal(content)
- pstr, err := NewHTTPPoster(2*time.Second, "http://localhost:8080/invalid", utils.ContentJSON, 3)
+ pstr, err := NewHTTPjsonMapEE(&config.EventExporterCfg{
+ ExportPath: "http://localhost:8080/invalid",
+ Attempts: 3,
+ FailedPostsDir: "/tmp",
+ }, config.CgrConfig(), nil, nil)
if err != nil {
t.Error(err)
}
- if err = pstr.PostValues(jsn, make(http.Header)); err == nil {
+ if err = ExportWithAttempts(pstr, &HTTPPosterRequest{Body: jsn, Header: make(http.Header)}, ""); err == nil {
t.Error("Expected error")
}
- AddFailedPost("http://localhost:8080/invalid", utils.ContentJSON, "test1", jsn, make(map[string]interface{}))
+ AddFailedPost("/tmp", "http://localhost:8080/invalid", utils.MetaHTTPjsonMap, "test1", jsn, make(map[string]interface{}))
time.Sleep(5 * time.Millisecond)
fs, err := filepath.Glob("/tmp/test1*")
if err != nil {
@@ -97,18 +100,21 @@ func TestHttpJsonPoster(t *testing.T) {
func TestHttpBytesPoster(t *testing.T) {
SetFailedPostCacheTTL(time.Millisecond)
- config.CgrConfig().GeneralCfg().FailedPostsDir = "/tmp"
content := []byte(`Test
Test2
`)
- pstr, err := NewHTTPPoster(2*time.Second, "http://localhost:8080/invalid", utils.ContentText, 3)
+ pstr, err := NewHTTPjsonMapEE(&config.EventExporterCfg{
+ ExportPath: "http://localhost:8080/invalid",
+ Attempts: 3,
+ FailedPostsDir: "/tmp",
+ }, config.CgrConfig(), nil, nil)
if err != nil {
t.Error(err)
}
- if err = pstr.PostValues(content, make(http.Header)); err == nil {
+ if err = ExportWithAttempts(pstr, &HTTPPosterRequest{Body: content, Header: make(http.Header)}, ""); err == nil {
t.Error("Expected error")
}
- AddFailedPost("http://localhost:8080/invalid", utils.ContentJSON, "test2", content, make(map[string]interface{}))
+ AddFailedPost("/tmp", "http://localhost:8080/invalid", utils.ContentJSON, "test2", content, make(map[string]interface{}))
time.Sleep(5 * time.Millisecond)
fs, err := filepath.Glob("/tmp/test2*")
if err != nil {
@@ -154,15 +160,19 @@ func TestSQSPoster(t *testing.T) {
body := "testString"
- pstr := NewSQSPoster(endpoint, 5, opts)
- if err := pstr.Post([]byte(body), ""); err != nil {
+ pstr := NewSQSee(&config.EventExporterCfg{
+ ExportPath: endpoint,
+ Attempts: 5,
+ Opts: opts,
+ }, nil)
+ if err := ExportWithAttempts(pstr, []byte(body), ""); err != nil {
t.Fatal(err)
}
var sess *session.Session
cfg := aws.Config{Endpoint: aws.String(endpoint)}
cfg.Region = aws.String(region)
-
+ var err error
cfg.Credentials = credentials.NewStaticCredentials(awsKey, awsSecret, "")
sess, err = session.NewSessionWithOptions(
session.Options{
@@ -233,8 +243,12 @@ func TestS3Poster(t *testing.T) {
body := "testString"
key := "key1234"
- pstr := NewS3Poster(endpoint, 5, opts)
- if err := pstr.Post([]byte(body), key); err != nil {
+ pstr := NewS3EE(&config.EventExporterCfg{
+ ExportPath: endpoint,
+ Attempts: 5,
+ Opts: opts,
+ }, nil)
+ if err := ExportWithAttempts(pstr, []byte(body), key); err != nil {
t.Fatal(err)
}
key += ".json"
@@ -243,6 +257,7 @@ func TestS3Poster(t *testing.T) {
cfg.Region = aws.String(region)
cfg.Credentials = credentials.NewStaticCredentials(awsKey, awsSecret, "")
+ var err error
sess, err = session.NewSessionWithOptions(
session.Options{
Config: cfg,
@@ -287,8 +302,12 @@ func TestAMQPv1Poster(t *testing.T) {
body := "testString"
- pstr := NewAMQPv1Poster(endpoint, 5, opts)
- if err := pstr.Post([]byte(body), ""); err != nil {
+ pstr := NewAMQPv1EE(&config.EventExporterCfg{
+ ExportPath: endpoint,
+ Attempts: 5,
+ Opts: opts,
+ }, nil)
+ if err := ExportWithAttempts(pstr, []byte(body), ""); err != nil {
t.Fatal(err)
}
// Create client
diff --git a/engine/poster_test.go b/ees/poster_test.go
similarity index 63%
rename from engine/poster_test.go
rename to ees/poster_test.go
index 4b9c500d8..b85c1a3d4 100644
--- a/engine/poster_test.go
+++ b/ees/poster_test.go
@@ -16,21 +16,22 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see
*/
-package engine
+package ees
import (
"reflect"
"testing"
+ "github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
-func TestAMQPPosterParseURL(t *testing.T) {
- amqp := &AMQPPoster{
- dialURL: "amqp://guest:guest@localhost:5672/?heartbeat=5",
+func TestAMQPeeParseURL(t *testing.T) {
+ amqp := &AMQPee{
+ cfg: &config.EventExporterCfg{ExportPath: "amqp://guest:guest@localhost:5672/?heartbeat=5"},
}
- expected := &AMQPPoster{
- dialURL: "amqp://guest:guest@localhost:5672/?heartbeat=5",
+ expected := &AMQPee{
+ cfg: &config.EventExporterCfg{ExportPath: "amqp://guest:guest@localhost:5672/?heartbeat=5"},
queueID: "q1",
exchange: "E1",
exchangeType: "fanout",
@@ -49,22 +50,16 @@ func TestAMQPPosterParseURL(t *testing.T) {
}
func TestKafkaParseURL(t *testing.T) {
- u := "127.0.0.1:9092"
- exp := &KafkaPoster{
- dialURL: "127.0.0.1:9092",
- topic: "cdr_billing",
- attempts: 10,
+ cfg := &config.EventExporterCfg{
+ ExportPath: "127.0.0.1:9092",
+ Attempts: 10,
+ Opts: map[string]interface{}{utils.KafkaTopic: "cdr_billing"},
}
- if kfk := NewKafkaPoster(u, 10, map[string]interface{}{utils.KafkaTopic: "cdr_billing"}); !reflect.DeepEqual(exp, kfk) {
- t.Errorf("Expected: %s ,received: %s", utils.ToJSON(exp), utils.ToJSON(kfk))
+ exp := &KafkaEE{
+ cfg: cfg,
+ topic: "cdr_billing",
}
- u = "localhost:9092"
- exp = &KafkaPoster{
- dialURL: "localhost:9092",
- topic: "cdr_billing",
- attempts: 10,
- }
- if kfk := NewKafkaPoster(u, 10, map[string]interface{}{utils.KafkaTopic: "cdr_billing"}); !reflect.DeepEqual(exp, kfk) {
+ if kfk := NewKafkaEE(cfg, nil); !reflect.DeepEqual(exp, kfk) {
t.Errorf("Expected: %s ,received: %s", utils.ToJSON(exp), utils.ToJSON(kfk))
}
}
diff --git a/ees/posterjsonmap.go b/ees/posterjsonmap.go
deleted file mode 100644
index a736d1f62..000000000
--- a/ees/posterjsonmap.go
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-Real-time Online/Offline Charging System (OerS) 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 ees
-
-import (
- "encoding/json"
- "strings"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/engine"
- "github.com/cgrates/cgrates/utils"
-)
-
-func NewPosterJSONMapEE(cgrCfg *config.CGRConfig, cfgIdx int, filterS *engine.FilterS,
- dc *utils.SafeMapStorage) (pstrJSON *PosterJSONMapEE, err error) {
- pstrJSON = &PosterJSONMapEE{
- id: cgrCfg.EEsCfg().Exporters[cfgIdx].ID,
- cgrCfg: cgrCfg,
- cfgIdx: cfgIdx,
- filterS: filterS,
- dc: dc,
- reqs: newConcReq(cgrCfg.EEsCfg().Exporters[cfgIdx].ConcurrentRequests),
- }
- switch cgrCfg.EEsCfg().Exporters[cfgIdx].Type {
- case utils.MetaAMQPV1jsonMap:
- pstrJSON.poster = engine.NewAMQPv1Poster(cgrCfg.EEsCfg().Exporters[cfgIdx].ExportPath,
- cgrCfg.EEsCfg().Exporters[cfgIdx].Attempts, cgrCfg.EEsCfg().Exporters[cfgIdx].Opts)
- case utils.MetaSQSjsonMap:
- pstrJSON.poster = engine.NewSQSPoster(cgrCfg.EEsCfg().Exporters[cfgIdx].ExportPath,
- cgrCfg.EEsCfg().Exporters[cfgIdx].Attempts, cgrCfg.EEsCfg().Exporters[cfgIdx].Opts)
- case utils.MetaKafkajsonMap:
- pstrJSON.poster = engine.NewKafkaPoster(cgrCfg.EEsCfg().Exporters[cfgIdx].ExportPath,
- cgrCfg.EEsCfg().Exporters[cfgIdx].Attempts, cgrCfg.EEsCfg().Exporters[cfgIdx].Opts)
- case utils.MetaS3jsonMap:
- pstrJSON.poster = engine.NewS3Poster(cgrCfg.EEsCfg().Exporters[cfgIdx].ExportPath,
- cgrCfg.EEsCfg().Exporters[cfgIdx].Attempts, cgrCfg.EEsCfg().Exporters[cfgIdx].Opts)
- }
- return
-}
-
-// PosterJSONMapEE implements EventExporter interface for .csv files
-type PosterJSONMapEE struct {
- id string
- cgrCfg *config.CGRConfig
- cfgIdx int // index of config instance within ERsCfg.Readers
- filterS *engine.FilterS
- poster engine.Poster
- dc *utils.SafeMapStorage
- reqs *concReq
-}
-
-// ID returns the identificator of this exporter
-func (pstrEE *PosterJSONMapEE) ID() string {
- return pstrEE.id
-}
-
-// OnEvicted implements EventExporter, doing the cleanup before exit
-func (pstrEE *PosterJSONMapEE) OnEvicted(string, interface{}) {
- pstrEE.poster.Close()
-}
-
-// ExportEvent implements EventExporter
-func (pstrEE *PosterJSONMapEE) ExportEvent(cgrEv *utils.CGREvent) (err error) {
- pstrEE.reqs.get()
- defer func() {
- updateEEMetrics(pstrEE.dc, cgrEv.ID, cgrEv.Event, err != nil, utils.FirstNonEmpty(pstrEE.cgrCfg.EEsCfg().Exporters[pstrEE.cfgIdx].Timezone,
- pstrEE.cgrCfg.GeneralCfg().DefaultTimezone))
- pstrEE.reqs.done()
- }()
- pstrEE.dc.Lock()
- pstrEE.dc.MapStorage[utils.NumberOfEvents] = pstrEE.dc.MapStorage[utils.NumberOfEvents].(int64) + 1
- pstrEE.dc.Unlock()
-
- valMp := make(map[string]interface{})
- if len(pstrEE.cgrCfg.EEsCfg().Exporters[pstrEE.cfgIdx].ContentFields()) == 0 {
- valMp = cgrEv.Event
- } else {
- oNm := map[string]*utils.OrderedNavigableMap{
- utils.MetaExp: utils.NewOrderedNavigableMap(),
- }
- eeReq := engine.NewExportRequest(map[string]utils.DataStorage{
- utils.MetaReq: utils.MapStorage(cgrEv.Event),
- utils.MetaDC: pstrEE.dc,
- utils.MetaOpts: utils.MapStorage(cgrEv.APIOpts),
- utils.MetaCfg: pstrEE.cgrCfg.GetDataProvider(),
- }, utils.FirstNonEmpty(cgrEv.Tenant, pstrEE.cgrCfg.GeneralCfg().DefaultTenant),
- pstrEE.filterS, oNm)
-
- if err = eeReq.SetFields(pstrEE.cgrCfg.EEsCfg().Exporters[pstrEE.cfgIdx].ContentFields()); err != nil {
- return
- }
- for el := eeReq.ExpData[utils.MetaExp].GetFirstElement(); el != nil; el = el.Next() {
- path := el.Value
- nmIt, _ := eeReq.ExpData[utils.MetaExp].Field(path)
- path = path[:len(path)-1] // remove the last index
- valMp[strings.Join(path, utils.NestingSep)] = nmIt.String()
- }
- }
-
- cgrID := utils.FirstNonEmpty(engine.MapEvent(cgrEv.Event).GetStringIgnoreErrors(utils.CGRID), utils.GenUUID())
- runID := utils.FirstNonEmpty(engine.MapEvent(cgrEv.Event).GetStringIgnoreErrors(utils.RunID), utils.MetaDefault)
- var body []byte
- if body, err = json.Marshal(valMp); err != nil {
- return
- }
- if err = pstrEE.poster.Post(body, utils.ConcatenatedKey(cgrID, runID)); err != nil &&
- pstrEE.cgrCfg.GeneralCfg().FailedPostsDir != utils.MetaNone {
- engine.AddFailedPost(pstrEE.cgrCfg.EEsCfg().Exporters[pstrEE.cfgIdx].ExportPath,
- pstrEE.cgrCfg.EEsCfg().Exporters[pstrEE.cfgIdx].Type, utils.EventExporterS, body,
- pstrEE.cgrCfg.EEsCfg().Exporters[pstrEE.cfgIdx].Opts)
- }
- return
-}
-
-func (pstrEE *PosterJSONMapEE) GetMetrics() *utils.SafeMapStorage {
- return pstrEE.dc.Clone()
-}
diff --git a/ees/posterjsonmap_test.go b/ees/posterjsonmap_test.go
index cd512f3d3..a4577f811 100644
--- a/ees/posterjsonmap_test.go
+++ b/ees/posterjsonmap_test.go
@@ -18,18 +18,7 @@ along with this program. If not, see
package ees
-import (
- "encoding/json"
- "reflect"
- "sync"
- "testing"
- "time"
-
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/engine"
- "github.com/cgrates/cgrates/utils"
-)
-
+/*
func TestPosterJsonMapID(t *testing.T) {
pstrEE := &PosterJSONMapEE{
id: "3",
@@ -487,3 +476,4 @@ func TestPosterJsonMapSyncLimit(t *testing.T) {
return
}
}
+*/
diff --git a/ees/s3.go b/ees/s3.go
new file mode 100644
index 000000000..8aedd8c29
--- /dev/null
+++ b/ees/s3.go
@@ -0,0 +1,138 @@
+/*
+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 ees
+
+import (
+ "bytes"
+ "fmt"
+ "sync"
+
+ "github.com/aws/aws-sdk-go/aws"
+ "github.com/aws/aws-sdk-go/aws/credentials"
+ "github.com/aws/aws-sdk-go/aws/session"
+ "github.com/aws/aws-sdk-go/service/s3/s3manager"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/utils"
+)
+
+// NewS3EE creates a s3 poster
+func NewS3EE(cfg *config.EventExporterCfg, dc *utils.SafeMapStorage) *S3EE {
+ pstr := &S3EE{
+ cfg: cfg,
+ dc: dc,
+ reqs: newConcReq(cfg.ConcurrentRequests),
+ }
+ pstr.parseOpts(cfg.Opts)
+ return pstr
+}
+
+// S3EE is a s3 poster
+type S3EE struct {
+ awsRegion string
+ awsID string
+ awsKey string
+ awsToken string
+ bucket string
+ folderPath string
+ session *session.Session
+ up *s3manager.Uploader
+
+ cfg *config.EventExporterCfg
+ dc *utils.SafeMapStorage
+ reqs *concReq
+ sync.RWMutex // protect connection
+ bytePreparing
+}
+
+func (pstr *S3EE) parseOpts(opts map[string]interface{}) {
+ pstr.bucket = utils.DefaultQueueID
+ if val, has := opts[utils.S3Bucket]; has {
+ pstr.bucket = utils.IfaceAsString(val)
+ }
+ if val, has := opts[utils.S3FolderPath]; has {
+ pstr.folderPath = utils.IfaceAsString(val)
+ }
+ if val, has := opts[utils.AWSRegion]; has {
+ pstr.awsRegion = utils.IfaceAsString(val)
+ }
+ if val, has := opts[utils.AWSKey]; has {
+ pstr.awsID = utils.IfaceAsString(val)
+ }
+ if val, has := opts[utils.AWSSecret]; has {
+ pstr.awsKey = utils.IfaceAsString(val)
+ }
+ if val, has := opts[utils.AWSToken]; has {
+ pstr.awsToken = utils.IfaceAsString(val)
+ }
+}
+
+func (pstr *S3EE) Cfg() *config.EventExporterCfg { return pstr.cfg }
+
+func (pstr *S3EE) Connect() (err error) {
+ pstr.Lock()
+ defer pstr.Unlock()
+ if pstr.session == nil {
+ cfg := aws.Config{Endpoint: aws.String(pstr.Cfg().ExportPath)}
+ if len(pstr.awsRegion) != 0 {
+ cfg.Region = aws.String(pstr.awsRegion)
+ }
+ if len(pstr.awsID) != 0 &&
+ len(pstr.awsKey) != 0 {
+ cfg.Credentials = credentials.NewStaticCredentials(pstr.awsID, pstr.awsKey, pstr.awsToken)
+ }
+ pstr.session, err = session.NewSessionWithOptions(
+ session.Options{
+ Config: cfg,
+ },
+ )
+ if err != nil {
+ return
+ }
+ }
+ if pstr.up == nil {
+ pstr.up, err = s3manager.NewUploader(pstr.session), nil
+ }
+ return
+}
+
+func (pstr *S3EE) ExportEvent(message interface{}, key string) (err error) {
+ pstr.reqs.get()
+ pstr.RLock()
+ _, err = pstr.up.Upload(&s3manager.UploadInput{
+ Bucket: aws.String(pstr.bucket),
+
+ // Can also use the `filepath` standard library package to modify the
+ // filename as need for an S3 object key. Such as turning absolute path
+ // to a relative path.
+ Key: aws.String(fmt.Sprintf("%s/%s.json", pstr.folderPath, key)),
+
+ // The file to be uploaded. io.ReadSeeker is preferred as the Uploader
+ // will be able to optimize memory when uploading large content. io.Reader
+ // is supported, but will require buffering of the reader's bytes for
+ // each part.
+ Body: bytes.NewReader(message.([]byte)),
+ })
+ pstr.RUnlock()
+ pstr.reqs.done()
+ return
+}
+
+func (pstr *S3EE) Close() (_ error) { return }
+
+func (pstr *S3EE) GetMetrics() *utils.SafeMapStorage { return pstr.dc }
diff --git a/ees/sql.go b/ees/sql.go
index 7e37c3154..ccff3fdcc 100644
--- a/ees/sql.go
+++ b/ees/sql.go
@@ -53,7 +53,6 @@ type SQLEe struct {
dialect gorm.Dialector
tableName string
- colNames []string
}
type sqlPosterRequest struct {
diff --git a/ees/sql_it_test.go b/ees/sql_it_test.go
index 0fed47fdd..d7d7d3831 100644
--- a/ees/sql_it_test.go
+++ b/ees/sql_it_test.go
@@ -230,22 +230,18 @@ func testSqlEeVerifyExportedEvent2(t *testing.T) {
}
func TestOpenDB1(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLMaxIdleConnsCfg] = 2
dialect := mysql.Open(fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&loc=Local&parseTime=true&sql_mode='ALLOW_INVALID_DATES'",
"cgrates", "CGRateS.org", "127.0.0.1", "3306", "cgrates"))
- _, _, err := openDB(cgrCfg, 0, dialect)
+ _, _, err := openDB(dialect, map[string]interface{}{utils.SQLMaxIdleConnsCfg: 2})
if err != nil {
t.Error(err)
}
}
func TestOpenDB1Err(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLMaxIdleConnsCfg] = "test"
dialect := mysql.Open(fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&loc=Local&parseTime=true&sql_mode='ALLOW_INVALID_DATES'",
"cgrates", "CGRateS.org", "127.0.0.1", "3306", "cgrates"))
- _, _, err := openDB(cgrCfg, 0, dialect)
+ _, _, err := openDB(dialect, map[string]interface{}{utils.SQLMaxIdleConnsCfg: "test"})
errExpect := "strconv.ParseInt: parsing \"test\": invalid syntax"
if err == nil || err.Error() != errExpect {
t.Errorf("Expected %v but received %v", errExpect, err)
@@ -253,22 +249,18 @@ func TestOpenDB1Err(t *testing.T) {
}
func TestOpenDB2(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLMaxOpenConns] = 2
dialect := mysql.Open(fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&loc=Local&parseTime=true&sql_mode='ALLOW_INVALID_DATES'",
"cgrates", "CGRateS.org", "127.0.0.1", "3306", "cgrates"))
- _, _, err := openDB(cgrCfg, 0, dialect)
+ _, _, err := openDB(dialect, map[string]interface{}{utils.SQLMaxOpenConns: 2})
if err != nil {
t.Error(err)
}
}
func TestOpenDB2Err(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLMaxOpenConns] = "test"
dialect := mysql.Open(fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&loc=Local&parseTime=true&sql_mode='ALLOW_INVALID_DATES'",
"cgrates", "CGRateS.org", "127.0.0.1", "3306", "cgrates"))
- _, _, err := openDB(cgrCfg, 0, dialect)
+ _, _, err := openDB(dialect, map[string]interface{}{utils.SQLMaxOpenConns: "test"})
errExpect := "strconv.ParseInt: parsing \"test\": invalid syntax"
if err == nil || err.Error() != errExpect {
t.Errorf("Expected %v but received %v", errExpect, err)
@@ -276,22 +268,18 @@ func TestOpenDB2Err(t *testing.T) {
}
func TestOpenDB3(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLMaxConnLifetime] = 2
dialect := mysql.Open(fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&loc=Local&parseTime=true&sql_mode='ALLOW_INVALID_DATES'",
"cgrates", "CGRateS.org", "127.0.0.1", "3306", "cgrates"))
- _, _, err := openDB(cgrCfg, 0, dialect)
+ _, _, err := openDB(dialect, map[string]interface{}{utils.SQLMaxConnLifetime: 2})
if err != nil {
t.Error(err)
}
}
func TestOpenDB3Err(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLMaxConnLifetime] = "test"
dialect := mysql.Open(fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&loc=Local&parseTime=true&sql_mode='ALLOW_INVALID_DATES'",
"cgrates", "CGRateS.org", "127.0.0.1", "3306", "cgrates"))
- _, _, err := openDB(cgrCfg, 0, dialect)
+ _, _, err := openDB(dialect, map[string]interface{}{utils.SQLMaxConnLifetime: "test"})
errExpect := "time: invalid duration \"test\""
if err == nil || err.Error() != errExpect {
t.Errorf("Expected %v but received %v", errExpect, err)
@@ -303,171 +291,15 @@ func TestSQLExportEvent1(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLTableNameOpt] = "expTable"
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLDBNameOpt] = "cgrates"
cgrCfg.EEsCfg().Exporters[0].ExportPath = `mysql://cgrates:CGRateS.org@127.0.0.1:3306`
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ sqlEe, err := NewSQLEe(cgrCfg.EEsCfg().Exporters[0], nil)
if err != nil {
t.Error(err)
}
- sqlEe, err := NewSQLEe(cgrCfg, 0, filterS, dc)
- if err != nil {
+ if err := sqlEe.Connect(); err != nil {
+ t.Fatal(err)
+ }
+ if err := sqlEe.ExportEvent(&sqlPosterRequest{Querry: "INSERT INTO expTable VALUES (); ", Values: []interface{}{}}, ""); err != nil {
t.Error(err)
}
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- if err := sqlEe.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- sqlEe.OnEvicted("test", "test")
-}
-
-func TestSQLExportEvent2(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLTableNameOpt] = "expTable"
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLDBNameOpt] = "cgrates"
- cgrCfg.EEsCfg().Exporters[0].ExportPath = `mysql://cgrates:CGRateS.org@127.0.0.1:3306`
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
- sqlEe, err := NewSQLEe(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.*row", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile(utils.MetaRow, utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- if err := sqlEe.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- sqlEe.OnEvicted("test", "test")
-}
-
-func TestSQLExportEvent3(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLTableNameOpt] = "expTable"
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLDBNameOpt] = "cgrates"
- cgrCfg.EEsCfg().Exporters[0].ExportPath = `mysql://cgrates:CGRateS.org@127.0.0.1:3306`
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
- sqlEe, err := NewSQLEe(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- if err := sqlEe.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- sqlEe.OnEvicted("test", "test")
-}
-
-func TestSQLExportEvent4(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLTableNameOpt] = "expTable"
- cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLDBNameOpt] = "cgrates"
- cgrCfg.EEsCfg().Exporters[0].ExportPath = `mysql://cgrates:CGRateS.org@127.0.0.1:3306`
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
- }
- sqlEe, err := NewSQLEe(cgrCfg, 0, filterS, dc)
- if err != nil {
- t.Error(err)
- }
- cgrEv.Event = map[string]interface{}{
- "test": "string",
- }
- cgrCfg.EEsCfg().Exporters[0].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field2", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[0].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[0].ComputeFields()
- errExpect := "inline parse error for string: <*wrong-type>"
- if err := sqlEe.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %v but received %v", errExpect, err)
- }
+ sqlEe.Close()
}
diff --git a/ees/sql_test.go b/ees/sql_test.go
index abfaf4f03..cae7b0ebd 100644
--- a/ees/sql_test.go
+++ b/ees/sql_test.go
@@ -24,7 +24,6 @@ import (
"testing"
"github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
@@ -32,27 +31,14 @@ import (
"gorm.io/gorm/logger"
)
-func TestSqlID(t *testing.T) {
- sqlEe := &SQLEe{
- id: "3",
- }
- if rcv := sqlEe.ID(); !reflect.DeepEqual(rcv, "3") {
- t.Errorf("Expected %+v but got %+v", "3", rcv)
- }
-}
-
func TestSqlGetMetrics(t *testing.T) {
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
sqlEe := &SQLEe{
dc: dc,
}
-
if rcv := sqlEe.GetMetrics(); !reflect.DeepEqual(rcv, sqlEe.dc) {
t.Errorf("Expected %+v but got %+v", utils.ToJSON(rcv), utils.ToJSON(sqlEe.dc))
}
@@ -63,21 +49,12 @@ func TestNewSQLeUrl(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLTableNameOpt] = "expTable"
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLDBNameOpt] = "postgres"
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SSLModeCfg] = "test"
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
+ sqlEe := &SQLEe{
+ cfg: cgrCfg.EEsCfg().Exporters[0],
+ reqs: newConcReq(0),
}
- sqlEe := &SQLEe{id: cgrCfg.EEsCfg().Exporters[0].ID,
- cgrCfg: cgrCfg, cfgIdx: 0, filterS: filterS, dc: dc}
- _, err = sqlEe.NewSQLEeUrl(cgrCfg)
errExpect := "db type <> not supported"
- if err == nil || err.Error() != errExpect {
+ if err := sqlEe.initDialector(); err == nil || err.Error() != errExpect {
t.Errorf("Expected %v but received %v", errExpect, err)
}
}
@@ -87,24 +64,16 @@ func TestNewSQLeUrlSQL(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLTableNameOpt] = "expTable"
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLDBNameOpt] = "mysql"
cgrCfg.EEsCfg().Exporters[0].ExportPath = `mysql://cgrates:CGRateS.org@127.0.0.1:3306`
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
+ sqlEe := &SQLEe{
+ cfg: cgrCfg.EEsCfg().Exporters[0],
+ reqs: newConcReq(0),
}
- sqlEe := &SQLEe{id: cgrCfg.EEsCfg().Exporters[0].ID,
- cgrCfg: cgrCfg, cfgIdx: 0, filterS: filterS, dc: dc}
dialectExpect := mysql.Open(fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&loc=Local&parseTime=true&sql_mode='ALLOW_INVALID_DATES'",
"cgrates", "CGRateS.org", "127.0.0.1", "3306", "mysql"))
- if dialect, err := sqlEe.NewSQLEeUrl(cgrCfg); err != nil {
+ if err := sqlEe.initDialector(); err != nil {
t.Error(err)
- } else if !reflect.DeepEqual(dialect, dialectExpect) {
- t.Errorf("Expected %v but received %v", utils.ToJSON(dialectExpect), utils.ToJSON(dialect))
+ } else if !reflect.DeepEqual(sqlEe.dialect, dialectExpect) {
+ t.Errorf("Expected %v but received %v", utils.ToJSON(dialectExpect), utils.ToJSON(sqlEe.dialect))
}
}
@@ -113,24 +82,16 @@ func TestNewSQLeUrlPostgres(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLTableNameOpt] = "expTable"
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLDBNameOpt] = "postgres"
cgrCfg.EEsCfg().Exporters[0].ExportPath = `postgres://cgrates:CGRateS.org@127.0.0.1:3306`
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
+ sqlEe := &SQLEe{
+ cfg: cgrCfg.EEsCfg().Exporters[0],
+ reqs: newConcReq(0),
}
- sqlEe := &SQLEe{id: cgrCfg.EEsCfg().Exporters[0].ID,
- cgrCfg: cgrCfg, cfgIdx: 0, filterS: filterS, dc: dc}
dialectExpect := postgres.Open(fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=%s",
"127.0.0.1", "3306", "postgres", "cgrates", "CGRateS.org", utils.SQLDefaultSSLMode))
- if dialect, err := sqlEe.NewSQLEeUrl(cgrCfg); err != nil {
+ if err := sqlEe.initDialector(); err != nil {
t.Error(err)
- } else if !reflect.DeepEqual(dialect, dialectExpect) {
- t.Errorf("Expected %v but received %v", utils.ToJSON(dialectExpect), utils.ToJSON(dialect))
+ } else if !reflect.DeepEqual(sqlEe.dialect, dialectExpect) {
+ t.Errorf("Expected %v but received %v", utils.ToJSON(dialectExpect), utils.ToJSON(sqlEe.dialect))
}
}
@@ -139,20 +100,12 @@ func TestNewSQLeExportPathError(t *testing.T) {
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLTableNameOpt] = "expTable"
cgrCfg.EEsCfg().Exporters[0].Opts[utils.SQLDBNameOpt] = "postgres"
cgrCfg.EEsCfg().Exporters[0].ExportPath = ":foo"
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
- t.Error(err)
+ sqlEe := &SQLEe{
+ cfg: cgrCfg.EEsCfg().Exporters[0],
+ reqs: newConcReq(0),
}
- sqlEe := &SQLEe{id: cgrCfg.EEsCfg().Exporters[0].ID,
- cgrCfg: cgrCfg, cfgIdx: 0, filterS: filterS, dc: dc}
errExpect := `parse ":foo": missing protocol scheme`
- if _, err := sqlEe.NewSQLEeUrl(cgrCfg); err == nil || err.Error() != errExpect {
+ if err := sqlEe.initDialector(); err == nil || err.Error() != errExpect {
t.Errorf("Expected %v but received %v", errExpect, err)
}
}
@@ -166,9 +119,8 @@ func (mockDialect2) Initialize(db *gorm.DB) error { return nil }
func TestOpenDBError2(t *testing.T) {
tmp := logger.Default
logger.Default = logger.Default.LogMode(logger.Silent)
- cgrCfg := config.NewDefaultCGRConfig()
mckDialect := new(mockDialect2)
- _, _, err := openDB(cgrCfg, 0, mckDialect)
+ _, _, err := openDB(mckDialect, make(map[string]interface{}))
errExpect := "invalid db"
if err == nil || err.Error() != errExpect {
t.Errorf("Expected %v but received %v", errExpect, err)
@@ -187,9 +139,8 @@ func (mockDialectErr) Initialize(db *gorm.DB) error {
func TestOpenDBError3(t *testing.T) {
tmp := logger.Default
logger.Default = logger.Default.LogMode(logger.Silent)
- cgrCfg := config.NewDefaultCGRConfig()
mckDialect := new(mockDialectErr)
- _, _, err := openDB(cgrCfg, 0, mckDialect)
+ _, _, err := openDB(mckDialect, make(map[string]interface{}))
errExpect := "NOT_FOUND"
if err == nil || err.Error() != errExpect {
t.Errorf("Expected %v but received %v", errExpect, err)
diff --git a/engine/pstr_sqs.go b/ees/sqs.go
similarity index 53%
rename from engine/pstr_sqs.go
rename to ees/sqs.go
index 05965db50..83f97d65f 100644
--- a/engine/pstr_sqs.go
+++ b/ees/sqs.go
@@ -16,49 +16,50 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see
*/
-package engine
+package ees
import (
- "fmt"
"sync"
- "time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sqs"
+ "github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
-// NewSQSPoster creates a poster for sqs
-func NewSQSPoster(dialURL string, attempts int, opts map[string]interface{}) Poster {
- pstr := &SQSPoster{
- attempts: attempts,
+// NewSQSee creates a poster for sqs
+func NewSQSee(cfg *config.EventExporterCfg, dc *utils.SafeMapStorage) *SQSee {
+ pstr := &SQSee{
+ cfg: cfg,
+ dc: dc,
+ reqs: newConcReq(cfg.ConcurrentRequests),
}
- pstr.parseOpts(opts)
+ pstr.parseOpts(cfg.Opts)
return pstr
}
-// SQSPoster is a poster for sqs
-type SQSPoster struct {
- sync.Mutex
- dialURL string
+// SQSee is a poster for sqs
+type SQSee struct {
awsRegion string
awsID string
awsKey string
awsToken string
- attempts int
queueURL *string
queueID string
- // getQueueOnce sync.Once
- session *session.Session
+ session *session.Session
+ svc *sqs.SQS
+
+ cfg *config.EventExporterCfg
+ dc *utils.SafeMapStorage
+ reqs *concReq
+ sync.RWMutex // protect connection
+ bytePreparing
}
-// Close for Poster interface
-func (pstr *SQSPoster) Close() {}
-
-func (pstr *SQSPoster) parseOpts(opts map[string]interface{}) {
+func (pstr *SQSee) parseOpts(opts map[string]interface{}) {
pstr.queueID = utils.DefaultQueueID
if val, has := opts[utils.SQSQueueID]; has {
pstr.queueID = utils.IfaceAsString(val)
@@ -75,20 +76,39 @@ func (pstr *SQSPoster) parseOpts(opts map[string]interface{}) {
if val, has := opts[utils.AWSToken]; has {
pstr.awsToken = utils.IfaceAsString(val)
}
- pstr.getQueueURL()
}
-func (pstr *SQSPoster) getQueueURL() (err error) {
- if pstr.queueURL != nil {
- return nil
+func (pstr *SQSee) Cfg() *config.EventExporterCfg { return pstr.cfg }
+
+func (pstr *SQSee) Connect() (err error) {
+ pstr.Lock()
+ defer pstr.Unlock()
+ if pstr.session == nil {
+ cfg := aws.Config{Endpoint: aws.String(pstr.Cfg().ExportPath)}
+ if len(pstr.awsRegion) != 0 {
+ cfg.Region = aws.String(pstr.awsRegion)
+ }
+ if len(pstr.awsID) != 0 &&
+ len(pstr.awsKey) != 0 {
+ cfg.Credentials = credentials.NewStaticCredentials(pstr.awsID, pstr.awsKey, pstr.awsToken)
+ }
+ pstr.session, err = session.NewSessionWithOptions(
+ session.Options{
+ Config: cfg,
+ },
+ )
+ if err != nil {
+ return
+ }
}
- // pstr.getQueueOnce.Do(func() {
- var svc *sqs.SQS
- if svc, err = pstr.newPosterSession(); err != nil {
+ if pstr.svc == nil {
+ pstr.svc = sqs.New(pstr.session)
+ }
+ if pstr.queueURL != nil {
return
}
var result *sqs.GetQueueUrlOutput
- if result, err = svc.GetQueueUrl(&sqs.GetQueueUrlInput{
+ if result, err = pstr.svc.GetQueueUrl(&sqs.GetQueueUrlInput{
QueueName: aws.String(pstr.queueID),
}); err == nil {
pstr.queueURL = new(string)
@@ -98,7 +118,7 @@ func (pstr *SQSPoster) getQueueURL() (err error) {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == sqs.ErrCodeQueueDoesNotExist {
// For CreateQueue
var createResult *sqs.CreateQueueOutput
- if createResult, err = svc.CreateQueue(&sqs.CreateQueueInput{
+ if createResult, err = pstr.svc.CreateQueue(&sqs.CreateQueueInput{
QueueName: aws.String(pstr.queueID),
}); err == nil {
pstr.queueURL = new(string)
@@ -106,70 +126,23 @@ func (pstr *SQSPoster) getQueueURL() (err error) {
return
}
}
- utils.Logger.Warning(fmt.Sprintf(" can not get url for queue with ID=%s because err: %v", pstr.queueID, err))
- // })
- return err
-}
-
-// Post is the method being called when we need to post anything in the queue
-func (pstr *SQSPoster) Post(message []byte, _ string) (err error) {
- var svc *sqs.SQS
- fib := utils.Fib()
-
- for i := 0; i < pstr.attempts; i++ {
- if svc, err = pstr.newPosterSession(); err == nil {
- break
- }
- if i+1 < pstr.attempts {
- time.Sleep(time.Duration(fib()) * time.Second)
- }
- }
- if err != nil {
- utils.Logger.Warning(fmt.Sprintf(" creating new session, err: %s", err.Error()))
- return
- }
-
- for i := 0; i < pstr.attempts; i++ {
- if _, err = svc.SendMessage(
- &sqs.SendMessageInput{
- MessageBody: aws.String(string(message)),
- QueueUrl: pstr.queueURL,
- },
- ); err == nil {
- break
- }
- if i+1 < pstr.attempts {
- time.Sleep(time.Duration(fib()) * time.Second)
- }
- }
- if err != nil {
- utils.Logger.Warning(fmt.Sprintf(" posting new message, err: %s", err.Error()))
- }
return
}
-func (pstr *SQSPoster) newPosterSession() (s *sqs.SQS, err error) {
- pstr.Lock()
- defer pstr.Unlock()
- if pstr.session == nil {
- var ses *session.Session
- cfg := aws.Config{Endpoint: aws.String(pstr.dialURL)}
- if len(pstr.awsRegion) != 0 {
- cfg.Region = aws.String(pstr.awsRegion)
- }
- if len(pstr.awsID) != 0 &&
- len(pstr.awsKey) != 0 {
- cfg.Credentials = credentials.NewStaticCredentials(pstr.awsID, pstr.awsKey, pstr.awsToken)
- }
- ses, err = session.NewSessionWithOptions(
- session.Options{
- Config: cfg,
- },
- )
- if err != nil {
- return nil, err
- }
- pstr.session = ses
- }
- return sqs.New(pstr.session), nil
+func (pstr *SQSee) ExportEvent(message interface{}, _ string) (err error) {
+ pstr.reqs.get()
+ pstr.RLock()
+ _, err = pstr.svc.SendMessage(
+ &sqs.SendMessageInput{
+ MessageBody: aws.String(string(message.([]byte))),
+ QueueUrl: pstr.queueURL,
+ },
+ )
+ pstr.RUnlock()
+ pstr.reqs.done()
+ return
}
+
+func (pstr *SQSee) Close() (_ error) { return }
+
+func (pstr *SQSee) GetMetrics() *utils.SafeMapStorage { return pstr.dc }
diff --git a/ees/virtualee_test.go b/ees/virtualee_test.go
index ae458819c..95d9ac56e 100644
--- a/ees/virtualee_test.go
+++ b/ees/virtualee_test.go
@@ -22,25 +22,11 @@ import (
"reflect"
"testing"
- "github.com/cgrates/cgrates/config"
- "github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
-func TestVirtualEeID(t *testing.T) {
- vEe := &VirtualEE{
- id: "3",
- }
- if rcv := vEe.ID(); !reflect.DeepEqual(rcv, "3") {
- t.Errorf("Expected %+v \n but got %+v", "3", rcv)
- }
-}
-
func TestVirtualEeGetMetrics(t *testing.T) {
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
+ dc, err := newEEMetrics("Local")
if err != nil {
t.Error(err)
}
@@ -53,68 +39,9 @@ func TestVirtualEeGetMetrics(t *testing.T) {
}
}
func TestVirtualEeExportEvent(t *testing.T) {
- cgrCfg := config.NewDefaultCGRConfig()
- cgrEv := new(utils.CGREvent)
- newIDb := engine.NewInternalDB(nil, nil, true)
- newDM := engine.NewDataManager(newIDb, cgrCfg.CacheCfg(), nil)
- filterS := engine.NewFilterS(cgrCfg, nil, newDM)
- dc, err := newEEMetrics(utils.FirstNonEmpty(
- "Local",
- utils.EmptyString,
- ))
- if err != nil {
+ vEe := &VirtualEE{}
+ if err := vEe.ExportEvent([]byte{}, ""); err != nil {
t.Error(err)
}
- vEe := &VirtualEE{
- id: "string",
- cgrCfg: cgrCfg,
- cfgIdx: 0,
- filterS: filterS,
- dc: dc,
- reqs: newConcReq(0),
- }
- cgrEv.Event = map[string]interface{}{
- "test1": "value",
- }
- cgrCfg.EEsCfg().Exporters[vEe.cfgIdx].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- },
- {
- Path: "*exp.2", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field2", utils.InfieldSep),
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[vEe.cfgIdx].Fields {
- field.ComputePath()
- }
- if err := vEe.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- cgrCfg.EEsCfg().Exporters[vEe.cfgIdx].ComputeFields()
- if err := vEe.ExportEvent(cgrEv); err != nil {
- t.Error(err)
- }
- cgrCfg.EEsCfg().Exporters[vEe.cfgIdx].Fields = []*config.FCTemplate{
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- {
- Path: "*exp.1", Type: utils.MetaVariable,
- Value: config.NewRSRParsersMustCompile("~*req.field1", utils.InfieldSep),
- Filters: []string{"*wrong-type"},
- },
- }
- for _, field := range cgrCfg.EEsCfg().Exporters[vEe.cfgIdx].Fields {
- field.ComputePath()
- }
- cgrCfg.EEsCfg().Exporters[vEe.cfgIdx].ComputeFields()
- errExpect := "inline parse error for string: <*wrong-type>"
- if err := vEe.ExportEvent(cgrEv); err == nil || err.Error() != errExpect {
- t.Errorf("Expected %q but received %q", errExpect, err)
- }
- vEe.OnEvicted("test", "test")
+ vEe.Close()
}
diff --git a/engine/action.go b/engine/action.go
index 7c45424f1..c8723a304 100644
--- a/engine/action.go
+++ b/engine/action.go
@@ -69,46 +69,50 @@ func (a *Action) Clone() (cln *Action) {
type actionTypeFunc func(*Account, *Action, Actions, interface{}) error
-func getActionFunc(typ string) (actionTypeFunc, bool) {
- actionFuncMap := map[string]actionTypeFunc{
- utils.MetaLog: logAction,
- utils.MetaResetTriggers: resetTriggersAction,
- utils.CDRLog: cdrLogAction,
- utils.MetaSetRecurrent: setRecurrentAction,
- utils.MetaUnsetRecurrent: unsetRecurrentAction,
- utils.MetaAllowNegative: allowNegativeAction,
- utils.MetaDenyNegative: denyNegativeAction,
- utils.MetaResetAccount: resetAccountAction,
- utils.MetaTopUpReset: topupResetAction,
- utils.MetaTopUp: topupAction,
- utils.MetaDebitReset: debitResetAction,
- utils.MetaDebit: debitAction,
- utils.MetaResetCounters: resetCountersAction,
- utils.MetaEnableAccount: enableAccountAction,
- utils.MetaDisableAccount: disableAccountAction,
- utils.MetaHTTPPost: callURL,
- utils.HttpPostAsync: callURLAsync,
- utils.MetaMailAsync: mailAsync,
- utils.MetaSetDDestinations: setddestinations,
- utils.MetaRemoveAccount: removeAccountAction,
- utils.MetaRemoveBalance: removeBalanceAction,
- utils.MetaSetBalance: setBalanceAction,
- utils.MetaTransferMonetaryDefault: transferMonetaryDefaultAction,
- utils.MetaCgrRpc: cgrRPCAction,
- utils.TopUpZeroNegative: topupZeroNegativeAction,
- utils.SetExpiry: setExpiryAction,
- utils.MetaPublishAccount: publishAccount,
- utils.MetaRemoveSessionCosts: removeSessionCosts,
- utils.MetaRemoveExpired: removeExpired,
- utils.MetaPostEvent: postEvent,
- utils.MetaCDRAccount: resetAccountCDR,
- utils.MetaExport: export,
- utils.MetaResetThreshold: resetThreshold,
- utils.MetaResetStatQueue: resetStatQueue,
- utils.MetaRemoteSetAccount: remoteSetAccount,
- }
- f, exists := actionFuncMap[typ]
- return f, exists
+var actionFuncMap = make(map[string]actionTypeFunc)
+
+func init() {
+ actionFuncMap[utils.MetaLog] = logAction
+ actionFuncMap[utils.MetaResetTriggers] = resetTriggersAction
+ actionFuncMap[utils.CDRLog] = cdrLogAction
+ actionFuncMap[utils.MetaSetRecurrent] = setRecurrentAction
+ actionFuncMap[utils.MetaUnsetRecurrent] = unsetRecurrentAction
+ actionFuncMap[utils.MetaAllowNegative] = allowNegativeAction
+ actionFuncMap[utils.MetaDenyNegative] = denyNegativeAction
+ actionFuncMap[utils.MetaResetAccount] = resetAccountAction
+ actionFuncMap[utils.MetaTopUpReset] = topupResetAction
+ actionFuncMap[utils.MetaTopUp] = topupAction
+ actionFuncMap[utils.MetaDebitReset] = debitResetAction
+ actionFuncMap[utils.MetaDebit] = debitAction
+ actionFuncMap[utils.MetaResetCounters] = resetCountersAction
+ actionFuncMap[utils.MetaEnableAccount] = enableAccountAction
+ actionFuncMap[utils.MetaDisableAccount] = disableAccountAction
+ actionFuncMap[utils.MetaMailAsync] = mailAsync
+ actionFuncMap[utils.MetaSetDDestinations] = setddestinations
+ actionFuncMap[utils.MetaRemoveAccount] = removeAccountAction
+ actionFuncMap[utils.MetaRemoveBalance] = removeBalanceAction
+ actionFuncMap[utils.MetaSetBalance] = setBalanceAction
+ actionFuncMap[utils.MetaTransferMonetaryDefault] = transferMonetaryDefaultAction
+ actionFuncMap[utils.MetaCgrRpc] = cgrRPCAction
+ actionFuncMap[utils.TopUpZeroNegative] = topupZeroNegativeAction
+ actionFuncMap[utils.SetExpiry] = setExpiryAction
+ actionFuncMap[utils.MetaPublishAccount] = publishAccount
+ actionFuncMap[utils.MetaRemoveSessionCosts] = removeSessionCosts
+ actionFuncMap[utils.MetaRemoveExpired] = removeExpired
+ actionFuncMap[utils.MetaCDRAccount] = resetAccountCDR
+ actionFuncMap[utils.MetaExport] = export
+ actionFuncMap[utils.MetaResetThreshold] = resetThreshold
+ actionFuncMap[utils.MetaResetStatQueue] = resetStatQueue
+ actionFuncMap[utils.MetaRemoteSetAccount] = remoteSetAccount
+}
+
+func getActionFunc(typ string) (f actionTypeFunc, exists bool) {
+ f, exists = actionFuncMap[typ]
+ return
+}
+
+func RegisterActionFunc(action string, f actionTypeFunc) {
+ actionFuncMap[action] = f
}
func logAction(ub *Account, a *Action, acs Actions, extraData interface{}) (err error) {
@@ -371,54 +375,6 @@ func genericReset(ub *Account) error {
return nil
}
-func getOneData(ub *Account, extraData interface{}) ([]byte, error) {
- switch {
- case ub != nil:
- return json.Marshal(ub)
- case extraData != nil:
- return json.Marshal(extraData)
- }
- return nil, nil
-}
-
-func callURL(ub *Account, a *Action, acs Actions, extraData interface{}) error {
- body, err := getOneData(ub, extraData)
- if err != nil {
- return err
- }
- pstr, err := NewHTTPPoster(config.CgrConfig().GeneralCfg().ReplyTimeout, a.ExtraParameters,
- utils.ContentJSON, config.CgrConfig().GeneralCfg().PosterAttempts)
- if err != nil {
- return err
- }
- err = pstr.PostValues(body, make(http.Header))
- if err != nil && config.CgrConfig().GeneralCfg().FailedPostsDir != utils.MetaNone {
- AddFailedPost(a.ExtraParameters, utils.MetaHTTPjson, utils.ActionsPoster+utils.HierarchySep+a.ActionType, body, make(map[string]interface{}))
- err = nil
- }
- return err
-}
-
-// Does not block for posts, no error reports
-func callURLAsync(ub *Account, a *Action, acs Actions, extraData interface{}) error {
- body, err := getOneData(ub, extraData)
- if err != nil {
- return err
- }
- pstr, err := NewHTTPPoster(config.CgrConfig().GeneralCfg().ReplyTimeout, a.ExtraParameters,
- utils.ContentJSON, config.CgrConfig().GeneralCfg().PosterAttempts)
- if err != nil {
- return err
- }
- go func() {
- err := pstr.PostValues(body, make(http.Header))
- if err != nil && config.CgrConfig().GeneralCfg().FailedPostsDir != utils.MetaNone {
- AddFailedPost(a.ExtraParameters, utils.MetaHTTPjson, utils.ActionsPoster+utils.HierarchySep+a.ActionType, body, make(map[string]interface{}))
- }
- }()
- return nil
-}
-
// Mails the balance hitting the threshold towards predefined list of addresses
func mailAsync(ub *Account, a *Action, acs Actions, extraData interface{}) error {
cgrCfg := config.CgrConfig()
@@ -941,24 +897,6 @@ func removeExpired(acc *Account, action *Action, _ Actions, extraData interface{
return nil
}
-func postEvent(ub *Account, a *Action, acs Actions, extraData interface{}) error {
- body, err := json.Marshal(extraData)
- if err != nil {
- return err
- }
- pstr, err := NewHTTPPoster(config.CgrConfig().GeneralCfg().ReplyTimeout, a.ExtraParameters,
- utils.ContentJSON, config.CgrConfig().GeneralCfg().PosterAttempts)
- if err != nil {
- return err
- }
- err = pstr.PostValues(body, make(http.Header))
- if err != nil && config.CgrConfig().GeneralCfg().FailedPostsDir != utils.MetaNone {
- AddFailedPost(a.ExtraParameters, utils.MetaHTTPjson, utils.ActionsPoster+utils.HierarchySep+a.ActionType, body, make(map[string]interface{}))
- err = nil
- }
- return err
-}
-
// resetAccountCDR resets the account out of values from CDR
func resetAccountCDR(ub *Account, action *Action, acts Actions, _ interface{}) error {
if ub == nil {
diff --git a/engine/caches.go b/engine/caches.go
index ee63be3fa..8948a7ebf 100644
--- a/engine/caches.go
+++ b/engine/caches.go
@@ -80,8 +80,6 @@ func init() {
gob.Register(new(StatAverage))
gob.Register(new(StatDistinct))
- gob.Register(new(HTTPPosterRequest))
-
gob.Register([]interface{}{})
gob.Register([]map[string]interface{}{})
gob.Register(map[string]interface{}{})
diff --git a/engine/libindex_health.go b/engine/libindex_health.go
index 0b213b94c..101bcb45f 100644
--- a/engine/libindex_health.go
+++ b/engine/libindex_health.go
@@ -528,7 +528,7 @@ func GetFltrIdxHealth(dm *DataManager, fltrCache, fltrIdxCache, objCache *ltcach
return
}
missingFltrs := utils.StringSet{} // for checking multiple filters that are missing(to not append the same ID in case)
- for _, id := range ids { // get all the objects from DB
+ for _, id := range ids { // get all the objects from DB
id = strings.TrimPrefix(id, objPrfx)
tntID := utils.NewTenantID(id)
var obj *objFIH
diff --git a/engine/poster.go b/engine/poster.go
deleted file mode 100644
index 1ee8e0023..000000000
--- a/engine/poster.go
+++ /dev/null
@@ -1,24 +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 engine
-
-type Poster interface {
- Post(body []byte, key string) error
- Close()
-}
diff --git a/engine/pstr_amqpv1.go b/engine/pstr_amqpv1.go
deleted file mode 100644
index e6e22d511..000000000
--- a/engine/pstr_amqpv1.go
+++ /dev/null
@@ -1,147 +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 engine
-
-import (
- "context"
- "fmt"
- "sync"
- "time"
-
- amqpv1 "github.com/Azure/go-amqp"
- "github.com/cgrates/cgrates/utils"
-)
-
-// NewAMQPv1Poster creates a poster for amqpv1
-func NewAMQPv1Poster(dialURL string, attempts int, opts map[string]interface{}) Poster {
- pstr := &AMQPv1Poster{
- dialURL: dialURL,
- queueID: "/" + utils.DefaultQueueID,
- attempts: attempts,
- }
- if vals, has := opts[utils.AMQPQueueID]; has {
- pstr.queueID = "/" + utils.IfaceAsString(vals)
- }
- return pstr
-}
-
-// AMQPv1Poster a poster for amqpv1
-type AMQPv1Poster struct {
- sync.Mutex
- dialURL string
- queueID string // identifier of the CDR queue where we publish
- attempts int
- client *amqpv1.Client
-}
-
-// Close closes the connections
-func (pstr *AMQPv1Poster) Close() {
- pstr.Lock()
- if pstr.client != nil {
- pstr.client.Close()
- }
- pstr.client = nil
- pstr.Unlock()
-}
-
-// Post is the method being called when we need to post anything in the queue
-func (pstr *AMQPv1Poster) Post(content []byte, _ string) (err error) {
- var s *amqpv1.Session
- fib := utils.Fib()
-
- for i := 0; i < pstr.attempts; i++ {
- if s, err = pstr.newPosterSession(); err == nil {
- break
- }
- // reset client and try again
- // used in case of closed connection because of idle time
- if pstr.client != nil {
- pstr.client.Close() // Make shure the connection is closed before reseting it
- }
- pstr.client = nil
- if i+1 < pstr.attempts {
- time.Sleep(time.Duration(fib()) * time.Second)
- }
- }
- if err != nil {
- utils.Logger.Warning(fmt.Sprintf(" creating new post channel, err: %s", err.Error()))
- return err
- }
-
- ctx := context.Background()
- for i := 0; i < pstr.attempts; i++ {
- sender, err := s.NewSender(
- amqpv1.LinkTargetAddress(pstr.queueID),
- )
- if err != nil {
- if i+1 < pstr.attempts {
- time.Sleep(time.Duration(fib()) * time.Second)
- }
- // if pstr.isRecoverableError(err) {
- // s.Close(ctx)
- // pstr.client.Close()
- // pstr.client = nil
- // stmp, err := pstr.newPosterSession()
- // if err == nil {
- // s = stmp
- // }
- // }
- continue
- }
- // Send message
- err = sender.Send(ctx, amqpv1.NewMessage(content))
- sender.Close(ctx)
- if err == nil {
- break
- }
- if i+1 < pstr.attempts {
- time.Sleep(time.Duration(fib()) * time.Second)
- }
- // if pstr.isRecoverableError(err) {
- // s.Close(ctx)
- // pstr.client.Close()
- // pstr.client = nil
- // stmp, err := pstr.newPosterSession()
- // if err == nil {
- // s = stmp
- // }
- // }
- }
- if err != nil {
- return
- }
- if s != nil {
- s.Close(ctx)
- }
- return
-}
-
-func (pstr *AMQPv1Poster) newPosterSession() (s *amqpv1.Session, err error) {
- pstr.Lock()
- defer pstr.Unlock()
- if pstr.client == nil {
- var client *amqpv1.Client
- client, err = amqpv1.Dial(pstr.dialURL)
- if err != nil {
- return nil, err
- }
- pstr.client = client
- }
- return pstr.client.NewSession()
-}
diff --git a/engine/pstr_http.go b/engine/pstr_http.go
deleted file mode 100644
index 8504fa7fb..000000000
--- a/engine/pstr_http.go
+++ /dev/null
@@ -1,123 +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 engine
-
-import (
- "bytes"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strings"
- "time"
-
- "github.com/cgrates/cgrates/utils"
-)
-
-type HTTPPosterRequest struct {
- Header http.Header
- Body interface{}
-}
-
-// NewHTTPPoster return a new HTTP poster
-func NewHTTPPoster(replyTimeout time.Duration, addr, contentType string,
- attempts int) (httposter *HTTPPoster, err error) {
- if !utils.SliceHasMember([]string{utils.ContentForm, utils.ContentJSON, utils.ContentText}, contentType) {
- return nil, fmt.Errorf("unsupported ContentType: %s", contentType)
- }
- return &HTTPPoster{
- httpClient: &http.Client{Transport: httpPstrTransport, Timeout: replyTimeout},
- addr: addr,
- contentType: contentType,
- attempts: attempts,
- }, nil
-}
-
-// HTTPPoster used to post cdrs
-type HTTPPoster struct {
- httpClient *http.Client
- addr string
- contentType string
- attempts int
-}
-
-// PostValues will post the event
-func (pstr *HTTPPoster) PostValues(content interface{}, hdr http.Header) (err error) {
- _, err = pstr.GetResponse(content, hdr)
- return
-}
-
-// GetResponse will post the event and return the response
-func (pstr *HTTPPoster) GetResponse(content interface{}, hdr http.Header) (respBody []byte, err error) {
- fib := utils.Fib()
- for i := 0; i < pstr.attempts; i++ {
- var req *http.Request
- if req, err = pstr.getRequest(content, hdr); err != nil {
- utils.Logger.Warning(fmt.Sprintf(" Posting to : <%s>, error creating request: <%s>", pstr.addr, err.Error()))
- return
- }
- if respBody, err = pstr.do(req); err != nil {
- if i+1 < pstr.attempts {
- time.Sleep(time.Duration(fib()) * time.Second)
- }
- continue
- }
- return
- }
- return
-}
-
-func (pstr *HTTPPoster) do(req *http.Request) (respBody []byte, err error) {
- var resp *http.Response
- if resp, err = pstr.httpClient.Do(req); err != nil {
- utils.Logger.Warning(fmt.Sprintf(" Posting to : <%s>, error: <%s>", pstr.addr, err.Error()))
- return
- }
- respBody, err = io.ReadAll(resp.Body)
- resp.Body.Close()
- if err != nil {
- utils.Logger.Warning(fmt.Sprintf(" Posting to : <%s>, error: <%s>", pstr.addr, err.Error()))
- return
- }
- if resp.StatusCode > 299 {
- err = fmt.Errorf("unexpected status code received: <%d>", resp.StatusCode)
- utils.Logger.Warning(fmt.Sprintf(" Posting to : <%s>, unexpected status code received: <%d>", pstr.addr, resp.StatusCode))
- return
- }
- return
-}
-
-func (pstr *HTTPPoster) getRequest(content interface{}, hdr http.Header) (req *http.Request, err error) {
- var body io.Reader
- if pstr.contentType == utils.ContentForm {
- body = strings.NewReader(content.(url.Values).Encode())
- } else {
- body = bytes.NewBuffer(content.([]byte))
- }
- contentType := "application/x-www-form-urlencoded"
- if pstr.contentType == utils.ContentJSON {
- contentType = "application/json"
- }
- hdr.Set("Content-Type", contentType)
- if req, err = http.NewRequest(http.MethodPost, pstr.addr, body); err != nil {
- return
- }
- req.Header = hdr
- return
-}
diff --git a/engine/pstr_kafka.go b/engine/pstr_kafka.go
deleted file mode 100644
index fdcadfacb..000000000
--- a/engine/pstr_kafka.go
+++ /dev/null
@@ -1,86 +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 engine
-
-import (
- "context"
- "sync"
-
- "github.com/cgrates/cgrates/utils"
- kafka "github.com/segmentio/kafka-go"
-)
-
-// NewKafkaPoster creates a kafka poster
-func NewKafkaPoster(dialURL string, attempts int, opts map[string]interface{}) *KafkaPoster {
- kfkPstr := &KafkaPoster{
- dialURL: dialURL,
- attempts: attempts,
- topic: utils.DefaultQueueID,
- }
- if vals, has := opts[utils.KafkaTopic]; has {
- kfkPstr.topic = utils.IfaceAsString(vals)
- }
- return kfkPstr
-}
-
-// KafkaPoster is a kafka poster
-type KafkaPoster struct {
- dialURL string
- topic string // identifier of the CDR queue where we publish
- attempts int
- sync.Mutex // protect writer
- writer *kafka.Writer
-}
-
-// Post is the method being called when we need to post anything in the queue
-// the optional chn will permits channel caching
-func (pstr *KafkaPoster) Post(content []byte, key string) (err error) {
- pstr.newPostWriter()
- pstr.Lock()
- if err = pstr.writer.WriteMessages(context.Background(), kafka.Message{
- Key: []byte(key),
- Value: content,
- }); err == nil {
- pstr.Unlock()
- return
- }
- pstr.Unlock()
- return
-}
-
-// Close closes the kafka writer
-func (pstr *KafkaPoster) Close() {
- pstr.Lock()
- if pstr.writer != nil {
- pstr.writer.Close()
- }
- pstr.writer = nil
- pstr.Unlock()
-}
-
-func (pstr *KafkaPoster) newPostWriter() {
- pstr.Lock()
- if pstr.writer == nil {
- pstr.writer = kafka.NewWriter(kafka.WriterConfig{
- Brokers: []string{pstr.dialURL},
- MaxAttempts: pstr.attempts,
- Topic: pstr.topic,
- })
- }
- pstr.Unlock()
-}
diff --git a/engine/pstr_s3.go b/engine/pstr_s3.go
deleted file mode 100644
index 6acc0174e..000000000
--- a/engine/pstr_s3.go
+++ /dev/null
@@ -1,152 +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 engine
-
-import (
- "bytes"
- "fmt"
- "sync"
- "time"
-
- "github.com/aws/aws-sdk-go/aws"
- "github.com/aws/aws-sdk-go/aws/credentials"
- "github.com/aws/aws-sdk-go/aws/session"
- "github.com/aws/aws-sdk-go/service/s3/s3manager"
- "github.com/cgrates/cgrates/utils"
-)
-
-// NewS3Poster creates a s3 poster
-func NewS3Poster(dialURL string, attempts int, opts map[string]interface{}) Poster {
- pstr := &S3Poster{
- dialURL: dialURL,
- attempts: attempts,
- }
- pstr.parseOpts(opts)
- return pstr
-}
-
-// S3Poster is a s3 poster
-type S3Poster struct {
- sync.Mutex
- dialURL string
- awsRegion string
- awsID string
- awsKey string
- awsToken string
- attempts int
- bucket string
- folderPath string
- session *session.Session
-}
-
-// Close for Poster interface
-func (pstr *S3Poster) Close() {}
-
-func (pstr *S3Poster) parseOpts(opts map[string]interface{}) {
- pstr.bucket = utils.DefaultQueueID
- if val, has := opts[utils.S3Bucket]; has {
- pstr.bucket = utils.IfaceAsString(val)
- }
- if val, has := opts[utils.S3FolderPath]; has {
- pstr.folderPath = utils.IfaceAsString(val)
- }
- if val, has := opts[utils.AWSRegion]; has {
- pstr.awsRegion = utils.IfaceAsString(val)
- }
- if val, has := opts[utils.AWSKey]; has {
- pstr.awsID = utils.IfaceAsString(val)
- }
- if val, has := opts[utils.AWSSecret]; has {
- pstr.awsKey = utils.IfaceAsString(val)
- }
- if val, has := opts[utils.AWSToken]; has {
- pstr.awsToken = utils.IfaceAsString(val)
- }
-}
-
-// Post is the method being called when we need to post anything in the queue
-func (pstr *S3Poster) Post(message []byte, key string) (err error) {
- var svc *s3manager.Uploader
- fib := utils.Fib()
-
- for i := 0; i < pstr.attempts; i++ {
- if svc, err = pstr.newPosterSession(); err == nil {
- break
- }
- if i+1 < pstr.attempts {
- time.Sleep(time.Duration(fib()) * time.Second)
- }
- }
- if err != nil {
- utils.Logger.Warning(fmt.Sprintf(" creating new session, err: %s", err.Error()))
- return
- }
-
- for i := 0; i < pstr.attempts; i++ {
- if _, err = svc.Upload(&s3manager.UploadInput{
- Bucket: aws.String(pstr.bucket),
-
- // Can also use the `filepath` standard library package to modify the
- // filename as need for an S3 object key. Such as turning absolute path
- // to a relative path.
- Key: aws.String(fmt.Sprintf("%s/%s.json", pstr.folderPath, key)),
-
- // The file to be uploaded. io.ReadSeeker is preferred as the Uploader
- // will be able to optimize memory when uploading large content. io.Reader
- // is supported, but will require buffering of the reader's bytes for
- // each part.
- Body: bytes.NewReader(message),
- }); err == nil {
- break
- }
- if i+1 < pstr.attempts {
- time.Sleep(time.Duration(fib()) * time.Second)
- }
- }
- if err != nil {
- utils.Logger.Warning(fmt.Sprintf(" posting new message, err: %s", err.Error()))
- }
- return
-}
-
-func (pstr *S3Poster) newPosterSession() (s *s3manager.Uploader, err error) {
- pstr.Lock()
- defer pstr.Unlock()
- if pstr.session == nil {
- var ses *session.Session
- cfg := aws.Config{Endpoint: aws.String(pstr.dialURL)}
- if len(pstr.awsRegion) != 0 {
- cfg.Region = aws.String(pstr.awsRegion)
- }
- if len(pstr.awsID) != 0 &&
- len(pstr.awsKey) != 0 {
- cfg.Credentials = credentials.NewStaticCredentials(pstr.awsID, pstr.awsKey, pstr.awsToken)
- }
- ses, err = session.NewSessionWithOptions(
- session.Options{
- Config: cfg,
- },
- )
- if err != nil {
- return nil, err
- }
- pstr.session = ses
- }
- return s3manager.NewUploader(pstr.session), nil
-}
diff --git a/engine/z_libindex_health_test.go b/engine/z_libindex_health_test.go
index 7e50d2c43..0f7a3da21 100644
--- a/engine/z_libindex_health_test.go
+++ b/engine/z_libindex_health_test.go
@@ -1081,8 +1081,8 @@ func TestHealthIndexDispatchers(t *testing.T) {
// we will set this dispatcherProfile but without indexing
dspPrf := &DispatcherProfile{
- Tenant: "cgrates.org",
- ID: "Dsp1",
+ Tenant: "cgrates.org",
+ ID: "Dsp1",
Subsystems: []string{utils.MetaAny, utils.MetaSessionS},
FilterIDs: []string{
"*string:~*opts.*apikey:dps1234|dsp9876",
@@ -1094,7 +1094,7 @@ func TestHealthIndexDispatchers(t *testing.T) {
Weight: 20,
Hosts: DispatcherHostProfiles{
{
- ID: "ALL",
+ ID: "ALL",
},
},
}
@@ -1105,11 +1105,11 @@ func TestHealthIndexDispatchers(t *testing.T) {
args := &IndexHealthArgsWith3Ch{}
exp := &FilterIHReply{
MissingIndexes: map[string][]string{
- "cgrates.org:*any:*string:*opts.*apikey:dps1234": {"Dsp1"},
- "cgrates.org:*any:*string:*opts.*apikey:dsp9876": {"Dsp1"},
- "cgrates.org:*any:*string:*req.AnswerTime:2013-11-07T08:42:26Z": {"Dsp1"},
- "cgrates.org:*sessions:*string:*opts.*apikey:dps1234": {"Dsp1"},
- "cgrates.org:*sessions:*string:*opts.*apikey:dsp9876": {"Dsp1"},
+ "cgrates.org:*any:*string:*opts.*apikey:dps1234": {"Dsp1"},
+ "cgrates.org:*any:*string:*opts.*apikey:dsp9876": {"Dsp1"},
+ "cgrates.org:*any:*string:*req.AnswerTime:2013-11-07T08:42:26Z": {"Dsp1"},
+ "cgrates.org:*sessions:*string:*opts.*apikey:dps1234": {"Dsp1"},
+ "cgrates.org:*sessions:*string:*opts.*apikey:dsp9876": {"Dsp1"},
"cgrates.org:*sessions:*string:*req.AnswerTime:2013-11-07T08:42:26Z": {"Dsp1"},
},
BrokenIndexes: map[string][]string{},
@@ -1117,17 +1117,17 @@ func TestHealthIndexDispatchers(t *testing.T) {
MissingObjects: []string{},
}
/*
- if rply, err := GetFltrIdxHealth(dm,
- ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
- ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
- ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
- utils.CacheDispatcherFilterIndexes); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(exp, rply) {
- t.Errorf("Expected %+v, received %+v", utils.ToJSON(exp), utils.ToJSON(rply))
- }
+ if rply, err := GetFltrIdxHealth(dm,
+ ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
+ ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
+ ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
+ utils.CacheDispatcherFilterIndexes); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(exp, rply) {
+ t.Errorf("Expected %+v, received %+v", utils.ToJSON(exp), utils.ToJSON(rply))
+ }
- */
+ */
// we will set manually some indexes that points to an nil object or index is valid but the obj is missing
indexes := map[string]utils.StringSet{
@@ -1140,7 +1140,7 @@ func TestHealthIndexDispatchers(t *testing.T) {
"Dsp2": {},
},
"*string:*req.ExtraField:Usage": { // index is valid but the obj does not exist
- "InexistingDispatcher": {},
+ "InexistingDispatcher": {},
"InexistingDispatcher2": {},
},
}
@@ -1152,15 +1152,15 @@ func TestHealthIndexDispatchers(t *testing.T) {
//get the newIdxHealth for dispatchersProfile
exp = &FilterIHReply{
MissingIndexes: map[string][]string{
- "cgrates.org:*any:*string:*opts.*apikey:dps1234": {"Dsp1"},
- "cgrates.org:*any:*string:*opts.*apikey:dsp9876": {"Dsp1"},
- "cgrates.org:*any:*string:*req.AnswerTime:2013-11-07T08:42:26Z": {"Dsp1"},
- "cgrates.org:*sessions:*string:*opts.*apikey:dps1234": {"Dsp1"},
- "cgrates.org:*sessions:*string:*opts.*apikey:dsp9876": {"Dsp1"},
+ "cgrates.org:*any:*string:*opts.*apikey:dps1234": {"Dsp1"},
+ "cgrates.org:*any:*string:*opts.*apikey:dsp9876": {"Dsp1"},
+ "cgrates.org:*any:*string:*req.AnswerTime:2013-11-07T08:42:26Z": {"Dsp1"},
+ "cgrates.org:*sessions:*string:*opts.*apikey:dps1234": {"Dsp1"},
+ "cgrates.org:*sessions:*string:*opts.*apikey:dsp9876": {"Dsp1"},
"cgrates.org:*sessions:*string:*req.AnswerTime:2013-11-07T08:42:26Z": {"Dsp1"},
},
- BrokenIndexes: map[string][]string{
- "cgrates.org:*suffix:*opts.Destination:+100": {"Dsp1"},
+ BrokenIndexes: map[string][]string{
+ "cgrates.org:*suffix:*opts.Destination:+100": {"Dsp1"},
"cgrates.org:*string:*req.RequestType:*rated": {"Dsp1"},
},
MissingFilters: map[string][]string{},
@@ -1171,26 +1171,26 @@ func TestHealthIndexDispatchers(t *testing.T) {
},
}
/*
- if rply, err := GetFltrIdxHealth(dm,
- ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
- ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
- ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
- utils.CacheDispatcherFilterIndexes); err != nil {
- t.Error(err)
- } else {
- sort.Strings(rply.MissingObjects)
- sort.Strings(exp.MissingObjects)
- if !reflect.DeepEqual(exp, rply) {
- t.Errorf("Expected %+v, received %+v", utils.ToJSON(exp), utils.ToJSON(rply))
+ if rply, err := GetFltrIdxHealth(dm,
+ ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
+ ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
+ ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
+ utils.CacheDispatcherFilterIndexes); err != nil {
+ t.Error(err)
+ } else {
+ sort.Strings(rply.MissingObjects)
+ sort.Strings(exp.MissingObjects)
+ if !reflect.DeepEqual(exp, rply) {
+ t.Errorf("Expected %+v, received %+v", utils.ToJSON(exp), utils.ToJSON(rply))
+ }
}
- }
- */
+ */
//we will use an inexisting Filter(not inline) for the same DispatcherProfile
dspPrf = &DispatcherProfile{
- Tenant: "cgrates.org",
- ID: "Dsp1",
+ Tenant: "cgrates.org",
+ ID: "Dsp1",
Subsystems: []string{utils.MetaAny, utils.MetaSessionS},
FilterIDs: []string{
"*string:~*opts.*apikey:dps1234|dsp9876",
@@ -1203,7 +1203,7 @@ func TestHealthIndexDispatchers(t *testing.T) {
Weight: 20,
Hosts: DispatcherHostProfiles{
{
- ID: "ALL",
+ ID: "ALL",
},
},
}
@@ -1214,15 +1214,15 @@ func TestHealthIndexDispatchers(t *testing.T) {
//get the newIdxHealth for dispatchersProfile
exp = &FilterIHReply{
MissingIndexes: map[string][]string{
- "cgrates.org:*any:*string:*opts.*apikey:dps1234": {"Dsp1"},
- "cgrates.org:*any:*string:*opts.*apikey:dsp9876": {"Dsp1"},
- "cgrates.org:*any:*string:*req.AnswerTime:2013-11-07T08:42:26Z": {"Dsp1"},
- "cgrates.org:*sessions:*string:*opts.*apikey:dps1234": {"Dsp1"},
- "cgrates.org:*sessions:*string:*opts.*apikey:dsp9876": {"Dsp1"},
+ "cgrates.org:*any:*string:*opts.*apikey:dps1234": {"Dsp1"},
+ "cgrates.org:*any:*string:*opts.*apikey:dsp9876": {"Dsp1"},
+ "cgrates.org:*any:*string:*req.AnswerTime:2013-11-07T08:42:26Z": {"Dsp1"},
+ "cgrates.org:*sessions:*string:*opts.*apikey:dps1234": {"Dsp1"},
+ "cgrates.org:*sessions:*string:*opts.*apikey:dsp9876": {"Dsp1"},
"cgrates.org:*sessions:*string:*req.AnswerTime:2013-11-07T08:42:26Z": {"Dsp1"},
},
- BrokenIndexes: map[string][]string{
- "cgrates.org:*suffix:*opts.Destination:+100": {"Dsp1"},
+ BrokenIndexes: map[string][]string{
+ "cgrates.org:*suffix:*opts.Destination:+100": {"Dsp1"},
"cgrates.org:*string:*req.RequestType:*rated": {"Dsp1"},
},
MissingFilters: map[string][]string{
@@ -1278,8 +1278,8 @@ func TestIndexHealthMultipleProfiles(t *testing.T) {
"*string:~*req.Account:1234",
"FLTR_1_NOT_EXIST2",
},
- RunID: "*default",
- Weight: 10,
+ RunID: "*default",
+ Weight: 10,
}
chPrf3 := &ChargerProfile{
Tenant: "cgrates.org",
@@ -1309,14 +1309,14 @@ func TestIndexHealthMultipleProfiles(t *testing.T) {
exp := &FilterIHReply{
MissingIndexes: map[string][]string{
"cgrates.org:*string:*opts.*eventType:ChargerAccountUpdate": {"Raw", "Default"},
- "cgrates.org:*string:*req.Account:1234": {"Raw", "Default", "Call_Attr1"},
- "cgrates.org:*prefix:*req.Destination:+2234": {"Default"},
- "cgrates.org:*suffix:*req.Usage:10":{"Default"},
+ "cgrates.org:*string:*req.Account:1234": {"Raw", "Default", "Call_Attr1"},
+ "cgrates.org:*prefix:*req.Destination:+2234": {"Default"},
+ "cgrates.org:*suffix:*req.Usage:10": {"Default"},
},
- BrokenIndexes: map[string][]string{},
+ BrokenIndexes: map[string][]string{},
MissingFilters: map[string][]string{
"cgrates.org:FLTR_1_NOT_EXIST2": {"Default", "Call_Attr1"},
- "cgrates.org:FLTR_1_NOT_EXIST": {"Call_Attr1"},
+ "cgrates.org:FLTR_1_NOT_EXIST": {"Call_Attr1"},
},
MissingObjects: []string{},
}
@@ -1369,12 +1369,12 @@ func TestIndexHealthReverseChecking(t *testing.T) {
// reverse indexes for charger
exp := map[string]*ReverseFilterIHReply{
- utils.CacheChargerFilterIndexes: {
- MissingFilters: map[string][]string{
- "cgrates.org:FLTR_1": {"Raw"},
+ utils.CacheChargerFilterIndexes: {
+ MissingFilters: map[string][]string{
+ "cgrates.org:FLTR_1": {"Raw"},
"cgrates.org:FLTR_2": {"Raw"},
},
- BrokenReverseIndexes: map[string][]string{},
+ BrokenReverseIndexes: map[string][]string{},
MissingReverseIndexes: map[string][]string{},
},
}
@@ -1390,8 +1390,8 @@ func TestIndexHealthReverseChecking(t *testing.T) {
// set reverse indexes for Raw that is already set and 2 that does not exist
indexes := map[string]utils.StringSet{
utils.CacheChargerFilterIndexes: {
- "Raw": {},
- "Default": {},
+ "Raw": {},
+ "Default": {},
"Call_Attr1": {},
},
}
@@ -1400,7 +1400,6 @@ func TestIndexHealthReverseChecking(t *testing.T) {
t.Error(err)
}
-
// reverse indexes for charger with the changes
exp = map[string]*ReverseFilterIHReply{
utils.CacheChargerFilterIndexes: {
@@ -1408,9 +1407,9 @@ func TestIndexHealthReverseChecking(t *testing.T) {
"cgrates.org:FLTR_1": {"Raw"},
"cgrates.org:FLTR_2": {"Raw"},
},
- BrokenReverseIndexes: map[string][]string{},
+ BrokenReverseIndexes: map[string][]string{},
MissingReverseIndexes: map[string][]string{},
- MissingObjects: []string{"cgrates.org:Default","cgrates.org:Call_Attr1" },
+ MissingObjects: []string{"cgrates.org:Default", "cgrates.org:Call_Attr1"},
},
}
if rply, err := GetRevFltrIdxHealth(dm,
@@ -1429,8 +1428,8 @@ func TestIndexHealthReverseChecking(t *testing.T) {
// reverse for a filter present in PROFILE but does not exist for the same indexes
indexes = map[string]utils.StringSet{
utils.CacheChargerFilterIndexes: {
- "Raw": {},
- "Default": {},
+ "Raw": {},
+ "Default": {},
"Call_Attr1": {},
},
}
@@ -1450,7 +1449,7 @@ func TestIndexHealthReverseChecking(t *testing.T) {
"cgrates.org:Raw": {"FLTR_NOT_IN_PROFILE"},
},
MissingReverseIndexes: map[string][]string{},
- MissingObjects: []string{"cgrates.org:Default","cgrates.org:Call_Attr1"},
+ MissingObjects: []string{"cgrates.org:Default", "cgrates.org:Call_Attr1"},
},
}
if rply, err := GetRevFltrIdxHealth(dm,
@@ -1540,7 +1539,7 @@ func TestIndexHealthMissingReverseIndexes(t *testing.T) {
exp := map[string]*ReverseFilterIHReply{
utils.CacheChargerFilterIndexes: {
- MissingFilters: map[string][]string{},
+ MissingFilters: map[string][]string{},
BrokenReverseIndexes: map[string][]string{},
MissingReverseIndexes: map[string][]string{
"cgrates.org:Raw": {"FLTR_1", "FLTR_3"},
@@ -1558,18 +1557,18 @@ func TestIndexHealthMissingReverseIndexes(t *testing.T) {
}
}
/*
- if err := dm.SetFilter(filter1, true); err != nil {
- t.Error(err)
- }
- if err := dm.SetFilter(filter2, true); err != nil {
- t.Error(err)
- }
- if err := dm.SetFilter(filter3, true); err != nil {
- t.Error(err)
- }
+ if err := dm.SetFilter(filter1, true); err != nil {
+ t.Error(err)
+ }
+ if err := dm.SetFilter(filter2, true); err != nil {
+ t.Error(err)
+ }
+ if err := dm.SetFilter(filter3, true); err != nil {
+ t.Error(err)
+ }
- */
- //Cache.Clear(nil)
+ */
+ //Cache.Clear(nil)
// we will set this multiple chargers but without indexing(same and different indexes)
chPrf1 = &ChargerProfile{
Tenant: "cgrates.org",
@@ -1590,7 +1589,7 @@ func TestIndexHealthMissingReverseIndexes(t *testing.T) {
}
exp = map[string]*ReverseFilterIHReply{
utils.CacheChargerFilterIndexes: {
- MissingFilters: map[string][]string{},
+ MissingFilters: map[string][]string{},
BrokenReverseIndexes: map[string][]string{},
MissingReverseIndexes: map[string][]string{
"cgrates.org:Raw": {"FLTR_1", "FLTR_3"}, // check for FLTR_2
@@ -1610,5 +1609,3 @@ func TestIndexHealthMissingReverseIndexes(t *testing.T) {
}
}
}
-
-
diff --git a/ers/amqp.go b/ers/amqp.go
index a0846f039..1d24f735b 100644
--- a/ers/amqp.go
+++ b/ers/amqp.go
@@ -255,8 +255,10 @@ func (rdr *AMQPER) createPoster() {
return
}
rdr.poster = ees.NewAMQPee(&config.EventExporterCfg{
- ExportPath: utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
- Attempts: rdr.cgrCfg.GeneralCfg().PosterAttempts,
- Opts: processedOpt,
+ ID: rdr.Config().ID,
+ ExportPath: utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
+ Attempts: rdr.cgrCfg.GeneralCfg().PosterAttempts,
+ Opts: processedOpt,
+ FailedPostsDir: rdr.cgrCfg.GeneralCfg().FailedPostsDir,
}, nil)
}
diff --git a/ers/amqpv1.go b/ers/amqpv1.go
index 64a9e973d..1cfefff09 100644
--- a/ers/amqpv1.go
+++ b/ers/amqpv1.go
@@ -27,6 +27,7 @@ import (
amqpv1 "github.com/Azure/go-amqp"
"github.com/cgrates/cgrates/agents"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -75,7 +76,7 @@ type AMQPv1ER struct {
conn *amqpv1.Client
ses *amqpv1.Session
- poster engine.Poster
+ poster *ees.AMQPv1EE
}
// Config returns the curent configuration
@@ -142,7 +143,7 @@ func (rdr *AMQPv1ER) readLoop(recv *amqpv1.Receiver) (err error) {
utils.ERs, err.Error()))
}
if rdr.poster != nil { // post it
- if err := rdr.poster.Post(body, utils.EmptyString); err != nil {
+ if err := ees.ExportWithAttempts(rdr.poster, body, utils.EmptyString); err != nil {
utils.Logger.Warning(
fmt.Sprintf("<%s> writing message error: %s",
utils.ERs, err.Error()))
@@ -205,6 +206,11 @@ func (rdr *AMQPv1ER) createPoster() {
len(rdr.Config().ProcessedPath) == 0 {
return
}
- rdr.poster = engine.NewAMQPv1Poster(utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
- rdr.cgrCfg.GeneralCfg().PosterAttempts, processedOpt)
+ rdr.poster = ees.NewAMQPv1EE(&config.EventExporterCfg{
+ ID: rdr.Config().ID,
+ ExportPath: utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
+ Attempts: rdr.cgrCfg.GeneralCfg().PosterAttempts,
+ Opts: processedOpt,
+ FailedPostsDir: rdr.cgrCfg.GeneralCfg().FailedPostsDir,
+ }, nil)
}
diff --git a/ers/kafka.go b/ers/kafka.go
index 68fa6128c..51448a49c 100644
--- a/ers/kafka.go
+++ b/ers/kafka.go
@@ -27,6 +27,7 @@ import (
"github.com/cgrates/cgrates/agents"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
@@ -79,7 +80,7 @@ type KafkaER struct {
rdrErr chan error
cap chan struct{}
- poster engine.Poster
+ poster *ees.KafkaEE
}
// Config returns the curent configuration
@@ -137,7 +138,7 @@ func (rdr *KafkaER) readLoop(r *kafka.Reader) {
utils.ERs, string(msg.Key), err.Error()))
}
if rdr.poster != nil { // post it
- if err := rdr.poster.Post(msg.Value, string(msg.Key)); err != nil {
+ if err := ees.ExportWithAttempts(rdr.poster, msg.Value, string(msg.Key)); err != nil {
utils.Logger.Warning(
fmt.Sprintf("<%s> writing message %s error: %s",
utils.ERs, string(msg.Key), err.Error()))
@@ -206,6 +207,11 @@ func (rdr *KafkaER) createPoster() {
len(rdr.Config().ProcessedPath) == 0 {
return
}
- rdr.poster = engine.NewKafkaPoster(utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
- rdr.cgrCfg.GeneralCfg().PosterAttempts, processedOpt)
+ rdr.poster = ees.NewKafkaEE(&config.EventExporterCfg{
+ ID: rdr.Config().ID,
+ ExportPath: utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
+ Attempts: rdr.cgrCfg.GeneralCfg().PosterAttempts,
+ Opts: processedOpt,
+ FailedPostsDir: rdr.cgrCfg.GeneralCfg().FailedPostsDir,
+ }, nil)
}
diff --git a/ers/kafka_test.go b/ers/kafka_test.go
index a8e909700..ef0e6ebee 100644
--- a/ers/kafka_test.go
+++ b/ers/kafka_test.go
@@ -24,6 +24,7 @@ import (
"time"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -133,7 +134,11 @@ func TestKafkaERServe2(t *testing.T) {
topic: "testTopic",
maxWait: time.Duration(1),
cap: make(chan struct{}, 1),
- poster: engine.NewKafkaPoster("url", 1, make(map[string]interface{})),
+ poster: ees.NewKafkaEE(&config.EventExporterCfg{
+ ExportPath: "url",
+ Attempts: 1,
+ Opts: make(map[string]interface{}),
+ }, nil),
}
rdr.rdrExit <- struct{}{}
rdr.Config().RunDelay = 1 * time.Millisecond
diff --git a/ers/nats.go b/ers/nats.go
index 17cee93b1..1d9c45400 100644
--- a/ers/nats.go
+++ b/ers/nats.go
@@ -187,10 +187,12 @@ func (rdr *NatsER) createPoster() (err error) {
return
}
rdr.poster, err = ees.NewNatsEE(&config.EventExporterCfg{
+ ID: rdr.Config().ID,
ExportPath: utils.FirstNonEmpty(
rdr.Config().ProcessedPath, rdr.Config().SourcePath),
- Opts: processedOpt,
- Attempts: rdr.cgrCfg.GeneralCfg().PosterAttempts,
+ Opts: processedOpt,
+ Attempts: rdr.cgrCfg.GeneralCfg().PosterAttempts,
+ FailedPostsDir: rdr.cgrCfg.GeneralCfg().FailedPostsDir,
}, rdr.cgrCfg.GeneralCfg().NodeID,
rdr.cgrCfg.GeneralCfg().ConnectTimeout, nil)
return
diff --git a/ers/s3.go b/ers/s3.go
index 95da213c1..648b2f09c 100644
--- a/ers/s3.go
+++ b/ers/s3.go
@@ -30,6 +30,7 @@ import (
"github.com/aws/aws-sdk-go/service/s3"
"github.com/cgrates/cgrates/agents"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -79,7 +80,7 @@ type S3ER struct {
bucket string
session *session.Session
- poster engine.Poster
+ poster *ees.S3EE
}
type s3Client interface {
@@ -197,8 +198,13 @@ func (rdr *S3ER) createPoster() {
len(rdr.Config().ProcessedPath) == 0 {
return
}
- rdr.poster = engine.NewS3Poster(utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
- rdr.cgrCfg.GeneralCfg().PosterAttempts, processedOpt)
+ rdr.poster = ees.NewS3EE(&config.EventExporterCfg{
+ ID: rdr.Config().ID,
+ ExportPath: utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
+ Attempts: rdr.cgrCfg.GeneralCfg().PosterAttempts,
+ Opts: processedOpt,
+ FailedPostsDir: rdr.cgrCfg.GeneralCfg().FailedPostsDir,
+ }, nil)
}
func (rdr *S3ER) isClosed() bool {
@@ -244,7 +250,7 @@ func (rdr *S3ER) readMsg(scv s3Client, key string) (err error) {
}
if rdr.poster != nil { // post it
- if err = rdr.poster.Post(msg, key); err != nil {
+ if err = ees.ExportWithAttempts(rdr.poster, msg, key); err != nil {
utils.Logger.Warning(
fmt.Sprintf("<%s> writing message %s error: %s",
utils.ERs, key, err.Error()))
diff --git a/ers/s3_test.go b/ers/s3_test.go
index 6b49fd51c..33c2e1706 100644
--- a/ers/s3_test.go
+++ b/ers/s3_test.go
@@ -27,6 +27,7 @@ import (
"github.com/aws/aws-sdk-go/service/s3"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -575,7 +576,11 @@ func TestS3ERReadMsgError5(t *testing.T) {
awsToken: "",
bucket: "cgrates_cdrs",
session: nil,
- poster: engine.NewSQSPoster("url", 1, make(map[string]interface{})),
+ poster: ees.NewS3EE(&config.EventExporterCfg{
+ ExportPath: "url",
+ Attempts: 1,
+ Opts: map[string]interface{}{},
+ }, nil),
}
rdr.Config().SourcePath = rdr.awsRegion
rdr.Config().ConcurrentReqs = -1
diff --git a/ers/sqs.go b/ers/sqs.go
index 506eea522..704f82ea6 100644
--- a/ers/sqs.go
+++ b/ers/sqs.go
@@ -30,6 +30,7 @@ import (
"github.com/aws/aws-sdk-go/service/sqs"
"github.com/cgrates/cgrates/agents"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -80,7 +81,7 @@ type SQSER struct {
queueID string
session *session.Session
- poster engine.Poster
+ poster *ees.SQSee
}
type sqsClient interface {
@@ -220,8 +221,13 @@ func (rdr *SQSER) createPoster() {
len(rdr.Config().ProcessedPath) == 0 {
return
}
- rdr.poster = engine.NewSQSPoster(utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
- rdr.cgrCfg.GeneralCfg().PosterAttempts, processedOpt)
+ rdr.poster = ees.NewSQSee(&config.EventExporterCfg{
+ ID: rdr.Config().ID,
+ ExportPath: utils.FirstNonEmpty(rdr.Config().ProcessedPath, rdr.Config().SourcePath),
+ Attempts: rdr.cgrCfg.GeneralCfg().PosterAttempts,
+ Opts: processedOpt,
+ FailedPostsDir: rdr.cgrCfg.GeneralCfg().FailedPostsDir,
+ }, nil)
}
func (rdr *SQSER) isClosed() bool {
@@ -254,7 +260,7 @@ func (rdr *SQSER) readMsg(scv sqsClient, msg *sqs.Message) (err error) {
}
if rdr.poster != nil { // post it
- if err = rdr.poster.Post(body, key); err != nil {
+ if err = ees.ExportWithAttempts(rdr.poster, body, key); err != nil {
utils.Logger.Warning(
fmt.Sprintf("<%s> writing message %s error: %s",
utils.ERs, key, err.Error()))
diff --git a/ers/sqs_test.go b/ers/sqs_test.go
index 8408ad7b8..8d98d8bdc 100644
--- a/ers/sqs_test.go
+++ b/ers/sqs_test.go
@@ -27,6 +27,7 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sqs"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -528,7 +529,11 @@ func TestSQSERReadMsgError3(t *testing.T) {
awsToken: "",
queueID: "cgrates_cdrs",
session: nil,
- poster: engine.NewSQSPoster("url", 1, make(map[string]interface{})),
+ poster: ees.NewSQSee(&config.EventExporterCfg{
+ ExportPath: "url",
+ Attempts: 1,
+ Opts: make(map[string]interface{}),
+ }, nil),
}
awsCfg := aws.Config{Endpoint: aws.String(rdr.Config().SourcePath)}
rdr.session, _ = session.NewSessionWithOptions(
diff --git a/general_tests/cdrs_exp_it_test.go b/general_tests/cdrs_exp_it_test.go
index b48e07094..a1632964b 100644
--- a/general_tests/cdrs_exp_it_test.go
+++ b/general_tests/cdrs_exp_it_test.go
@@ -38,6 +38,7 @@ import (
v1 "github.com/cgrates/cgrates/apier/v1"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
kafka "github.com/segmentio/kafka-go"
@@ -329,7 +330,7 @@ func testCDRsExpKafka(t *testing.T) {
cancel()
}
-func checkContent(ev *engine.ExportEvents, content []interface{}) error {
+func checkContent(ev *ees.ExportEvents, content []interface{}) error {
match := false
for _, bev := range ev.Events {
for _, con := range content {
@@ -367,7 +368,7 @@ func testCDRsExpFileFailover(t *testing.T) {
fileName := file.Name()
filePath := path.Join(cdrsExpCfg.GeneralCfg().FailedPostsDir, fileName)
- ev, err := engine.NewExportEventsFromFile(filePath)
+ ev, err := ees.NewExportEventsFromFile(filePath)
if err != nil {
t.Errorf("<%s> for file <%s>", err, fileName)
continue
diff --git a/general_tests/cdrs_onlexp_it_test.go b/general_tests/cdrs_onlexp_it_test.go
index 5ed8252b6..45d1f7285 100644
--- a/general_tests/cdrs_onlexp_it_test.go
+++ b/general_tests/cdrs_onlexp_it_test.go
@@ -34,6 +34,7 @@ import (
"time"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/rpcclient"
@@ -452,8 +453,8 @@ func testCDRsOnExpFileFailover(t *testing.T) {
v2 := url.Values{}
v1.Set("OriginID", "httpjsonrpc1")
v2.Set("OriginID", "amqpreconnect")
- httpContent := []interface{}{&engine.HTTPPosterRequest{Body: v1, Header: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}}},
- &engine.HTTPPosterRequest{Body: v2, Header: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}}}}
+ httpContent := []interface{}{&ees.HTTPPosterRequest{Body: v1, Header: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}}},
+ &ees.HTTPPosterRequest{Body: v2, Header: http.Header{"Content-Type": []string{"application/x-www-form-urlencoded"}}}}
filesInDir, _ := os.ReadDir(cdrsMasterCfg.GeneralCfg().FailedPostsDir)
if len(filesInDir) == 0 {
t.Fatalf("No files in directory: %s", cdrsMasterCfg.GeneralCfg().FailedPostsDir)
@@ -462,7 +463,7 @@ func testCDRsOnExpFileFailover(t *testing.T) {
fileName := file.Name()
filePath := path.Join(cdrsMasterCfg.GeneralCfg().FailedPostsDir, fileName)
- ev, err := engine.NewExportEventsFromFile(filePath)
+ ev, err := ees.NewExportEventsFromFile(filePath)
if err != nil {
t.Errorf("<%s> for file <%s>", err, fileName)
continue
diff --git a/general_tests/cdrs_post_failover_it_test.go b/general_tests/cdrs_post_failover_it_test.go
index f50d7b038..eed4a9386 100644
--- a/general_tests/cdrs_post_failover_it_test.go
+++ b/general_tests/cdrs_post_failover_it_test.go
@@ -28,6 +28,7 @@ import (
"time"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -192,7 +193,7 @@ func testCDRsPostFailoverToFile(t *testing.T) {
fileName := file.Name()
filePath := path.Join(cdrsPostFailCfg.GeneralCfg().FailedPostsDir, fileName)
- ev, err := engine.NewExportEventsFromFile(filePath)
+ ev, err := ees.NewExportEventsFromFile(filePath)
if err != nil {
t.Errorf("<%s> for file <%s>", err, fileName)
continue
diff --git a/general_tests/cdrs_processevent_it_test.go b/general_tests/cdrs_processevent_it_test.go
index 85873c935..923c3ad5c 100644
--- a/general_tests/cdrs_processevent_it_test.go
+++ b/general_tests/cdrs_processevent_it_test.go
@@ -32,6 +32,7 @@ import (
v2 "github.com/cgrates/cgrates/apier/v2"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -581,7 +582,7 @@ func testV1CDRsProcessEventExportCheck(t *testing.T) {
if strings.HasPrefix(fileName, "EventExporterS|") {
foundFile = true
filePath := path.Join(pecdrsCfg.GeneralCfg().FailedPostsDir, fileName)
- ev, err := engine.NewExportEventsFromFile(filePath)
+ ev, err := ees.NewExportEventsFromFile(filePath)
if err != nil {
t.Fatal(err)
} else if len(ev.Events) == 0 {
diff --git a/general_tests/poster_it_test.go b/general_tests/poster_it_test.go
index 05713b02a..d615c9478 100644
--- a/general_tests/poster_it_test.go
+++ b/general_tests/poster_it_test.go
@@ -29,6 +29,7 @@ import (
"time"
"github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
@@ -111,7 +112,7 @@ func testPosterITRpcConn(t *testing.T) {
}
}
-func testPosterReadFolder(format string) (expEv *engine.ExportEvents, err error) {
+func testPosterReadFolder(format string) (expEv *ees.ExportEvents, err error) {
filesInDir, _ := os.ReadDir(pstrCfg.GeneralCfg().FailedPostsDir)
if len(filesInDir) == 0 {
err = fmt.Errorf("No files in directory: %s", pstrCfg.GeneralCfg().FailedPostsDir)
@@ -121,7 +122,7 @@ func testPosterReadFolder(format string) (expEv *engine.ExportEvents, err error)
fileName := file.Name()
filePath := path.Join(pstrCfg.GeneralCfg().FailedPostsDir, fileName)
- expEv, err = engine.NewExportEventsFromFile(filePath)
+ expEv, err = ees.NewExportEventsFromFile(filePath)
if err != nil {
return
}
diff --git a/services/globalvars.go b/services/globalvars.go
index c8eca06e9..940f85f02 100644
--- a/services/globalvars.go
+++ b/services/globalvars.go
@@ -23,6 +23,7 @@ import (
"net/http"
"sync"
+ "github.com/cgrates/cgrates/ees"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/config"
@@ -48,7 +49,7 @@ type GlobalVarS struct {
// Start should handle the sercive start
func (gv *GlobalVarS) Start() (err error) {
engine.SetRoundingDecimals(gv.cfg.GeneralCfg().RoundingDecimals)
- engine.SetFailedPostCacheTTL(gv.cfg.GeneralCfg().FailedPostsTTL)
+ ees.SetFailedPostCacheTTL(gv.cfg.GeneralCfg().FailedPostsTTL)
return gv.initHTTPTransport()
}
diff --git a/utils/consts.go b/utils/consts.go
index 38991ced6..bb424b8ef 100644
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -28,20 +28,7 @@ var (
PreRated, CostSource, CostDetails, ExtraInfo, OrderID})
PostPaidRatedSlice = []string{MetaPostpaid, MetaRated}
- GitLastLog string // If set, it will be processed as part of versioning
- PosterTransportContentTypes = map[string]string{
- MetaHTTPjsonCDR: ContentJSON,
- MetaHTTPjsonMap: ContentJSON,
- MetaHTTPjson: ContentJSON,
- MetaHTTPPost: ContentForm,
- MetaAMQPjsonCDR: ContentJSON,
- MetaAMQPjsonMap: ContentJSON,
- MetaAMQPV1jsonMap: ContentJSON,
- MetaSQSjsonMap: ContentJSON,
- MetaKafkajsonMap: ContentJSON,
- MetaS3jsonMap: ContentJSON,
- MetaNatsjsonMap: ContentJSON,
- }
+ GitLastLog string // If set, it will be processed as part of versioning
extraDBPartition = NewStringSet([]string{CacheDispatchers,
CacheDispatcherRoutes, CacheDispatcherLoads, CacheDiameterMessages, CacheRPCResponses, CacheClosedSessions,
@@ -318,7 +305,6 @@ const (
MetaConstant = "*constant"
MetaFiller = "*filler"
MetaHTTPPost = "*http_post"
- MetaHTTPjson = "*http_json"
MetaHTTPjsonCDR = "*http_json_cdr"
MetaHTTPjsonMap = "*http_json_map"
MetaAMQPjsonCDR = "*amqp_json_cdr"
@@ -434,7 +420,6 @@ const (
FWVSuffix = ".fwv"
ContentJSON = "json"
ContentForm = "form"
- ContentText = "text"
FileLockPrefix = "file_"
ActionsPoster = "act"
CDRPoster = "cdr"
diff --git a/utils/struct.go b/utils/struct.go
index 8bf6528df..d10026eff 100644
--- a/utils/struct.go
+++ b/utils/struct.go
@@ -58,7 +58,7 @@ func MissingStructFields(s interface{}, mandatories []string) []string {
sType := sValue.Type()
for _, fieldName := range mandatories {
fldStr, ok := sType.FieldByName(fieldName)
- if !ok || fieldByIndexIsEmpty(sValue, fldStr.Index){
+ if !ok || fieldByIndexIsEmpty(sValue, fldStr.Index) {
missing = append(missing, fieldName)
}
}