diff --git a/ees/ee.go b/ees/ee.go index edbbb60d7..f31cbbb01 100644 --- a/ees/ee.go +++ b/ees/ee.go @@ -43,11 +43,10 @@ type EventExporter interface { func NewEventExporter(cfg *config.EventExporterCfg, cgrCfg *config.CGRConfig, filterS *engine.FilterS, connMngr *engine.ConnManager) (ee EventExporter, err error) { timezone := utils.FirstNonEmpty(cfg.Timezone, cgrCfg.GeneralCfg().DefaultTimezone) - loc, err := time.LoadLocation(timezone) + em, err := utils.NewExporterMetrics(cfg.MetricsResetSchedule, timezone) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to initialize exporter metrics: %v", err) } - em := utils.NewExporterMetrics(cfg.MetricsResetSchedule, loc) switch cfg.Type { case utils.MetaFileCSV: diff --git a/ees/ee_test.go b/ees/ee_test.go index 66f764273..df087c99c 100644 --- a/ees/ee_test.go +++ b/ees/ee_test.go @@ -23,7 +23,6 @@ import ( "reflect" "strings" "testing" - "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" @@ -40,7 +39,10 @@ func TestNewEventExporter(t *testing.T) { if strings.Contains(errExpect, err.Error()) { t.Errorf("Expected %+v but got %+v", errExpect, err) } - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } eeExpect, err := NewFileCSVee(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS, em) if strings.Contains(errExpect, err.Error()) { t.Errorf("Expected %+v but got %+v", errExpect, err) @@ -67,8 +69,10 @@ func TestNewEventExporterCase2(t *testing.T) { if strings.Contains(errExpect, err.Error()) { t.Errorf("Expected %+v but got %+v", errExpect, err) } - - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } eeExpect, err := NewFileFWVee(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS, em) if strings.Contains(errExpect, err.Error()) { t.Errorf("Expected %+v but got %+v", errExpect, err) @@ -93,7 +97,10 @@ func TestNewEventExporterCase3(t *testing.T) { if err != nil { t.Error(err) } - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } eeExpect, err := NewHTTPPostEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS, em) if err != nil { t.Error(err) @@ -115,7 +122,10 @@ func TestNewEventExporterCase4(t *testing.T) { if err != nil { t.Error(err) } - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } eeExpect, err := NewHTTPjsonMapEE(cgrCfg.EEsCfg().Exporters[0], cgrCfg, filterS, em) if err != nil { t.Error(err) @@ -137,7 +147,10 @@ func TestNewEventExporterCase6(t *testing.T) { if err != nil { t.Error(err) } - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } eeExpect := NewVirtualEE(cgrCfg.EEsCfg().Exporters[0], em) newEE := ee.(*VirtualEE) newEE.em.MapStorage[utils.TimeNow] = nil @@ -170,9 +183,9 @@ func TestNewEventExporterCase7(t *testing.T) { if err != nil { t.Error(err) } - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") if err != nil { - t.Error(err) + t.Fatal(err) } eeExpect, err := NewElasticEE(cgrCfg.EEsCfg().Exporters[0], em) if err != nil { @@ -200,12 +213,12 @@ func TestNewEventExporterCase8(t *testing.T) { } } -// Test for invalid "dc" -func TestNewEventExporterDcCase(t *testing.T) { +// Test for invalid "em" +func TestNewEventExporterEmCase(t *testing.T) { cgrCfg := config.NewDefaultCGRConfig() cgrCfg.GeneralCfg().DefaultTimezone = "invalid_timezone" _, err := NewEventExporter(cgrCfg.EEsCfg().Exporters[0], cgrCfg, nil, nil) - errExpect := "unknown time zone invalid_timezone" + errExpect := "failed to initialize exporter metrics: 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_test.go b/ees/ees_test.go index 429bd7780..5a39c0728 100644 --- a/ees/ees_test.go +++ b/ees/ees_test.go @@ -438,7 +438,10 @@ func TestOnCacheEvicted(t *testing.T) { } func TestUpdateEEMetrics(t *testing.T) { - em := utils.NewExporterMetrics("", time.UTC) + em, err := utils.NewExporterMetrics("", "") + if err != nil { + t.Fatal(err) + } tnow := time.Now() ev := engine.MapEvent{ utils.AnswerTime: tnow, @@ -447,7 +450,10 @@ func TestUpdateEEMetrics(t *testing.T) { utils.ToR: utils.MetaVoice, utils.Usage: time.Second, } - exp := utils.NewExporterMetrics("", time.UTC) + exp, err := utils.NewExporterMetrics("", "") + if err != nil { + t.Fatal(err) + } exp.MapStorage[utils.FirstEventATime] = tnow exp.MapStorage[utils.LastEventATime] = tnow exp.MapStorage[utils.FirstExpOrderID] = int64(1) diff --git a/ees/elastic_test.go b/ees/elastic_test.go index e3dd0e06b..60e19f913 100644 --- a/ees/elastic_test.go +++ b/ees/elastic_test.go @@ -20,7 +20,6 @@ package ees import ( "reflect" "testing" - "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" @@ -28,7 +27,10 @@ import ( ) func TestGetMetrics(t *testing.T) { - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } ee := &ElasticEE{ em: em, } @@ -59,7 +61,10 @@ func TestInitClient(t *testing.T) { func TestElasticExportEventErr(t *testing.T) { cgrCfg := config.NewDefaultCGRConfig() - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } eEe, err := NewElasticEE(cgrCfg.EEsCfg().Exporters[0], em) if err != nil { t.Error(err) diff --git a/ees/filecsv_it_test.go b/ees/filecsv_it_test.go index 08352dc74..687a90e60 100644 --- a/ees/filecsv_it_test.go +++ b/ees/filecsv_it_test.go @@ -677,7 +677,10 @@ func TestCsvInitFileCSV(t *testing.T) { if err := os.MkdirAll("/tmp/TestInitFileCSV", 0666); err != nil { t.Error(err) } - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } fCsv := &FileCSVee{ cgrCfg: cgrCfg, cfg: cgrCfg.EEsCfg().Exporters[0], diff --git a/ees/filecsv_test.go b/ees/filecsv_test.go index 7511e0e60..13bc8fd6c 100644 --- a/ees/filecsv_test.go +++ b/ees/filecsv_test.go @@ -24,7 +24,6 @@ import ( "io" "reflect" "testing" - "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" @@ -32,7 +31,10 @@ import ( ) func TestFileCsvGetMetrics(t *testing.T) { - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } fCsv := &FileCSVee{em: em} if rcv := fCsv.GetMetrics(); !reflect.DeepEqual(rcv, fCsv.em) { @@ -179,7 +181,10 @@ func TestFileCsvExportEvent(t *testing.T) { filterS := engine.NewFilterS(cfg, nil, newDM) byteBuff := new(bytes.Buffer) csvNW := csv.NewWriter(byteBuff) - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } fCsv := &FileCSVee{ cfg: cfg.EEsCfg().Exporters[0], cgrCfg: cfg, diff --git a/ees/filefwv_it_test.go b/ees/filefwv_it_test.go index 9ef8d27be..23df3571a 100644 --- a/ees/filefwv_it_test.go +++ b/ees/filefwv_it_test.go @@ -164,7 +164,10 @@ func TestFileFwvInit(t *testing.T) { if err := os.MkdirAll("/tmp/TestInitFileFWV", 0666); err != nil { t.Error(err) } - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } fFwv := &FileFWVee{ cgrCfg: cgrCfg, cfg: cgrCfg.EEsCfg().Exporters[0], diff --git a/ees/filefwv_test.go b/ees/filefwv_test.go index e473d88a5..0af7b4167 100644 --- a/ees/filefwv_test.go +++ b/ees/filefwv_test.go @@ -24,7 +24,6 @@ import ( "io" "reflect" "testing" - "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" @@ -32,7 +31,10 @@ import ( ) func TestFileFwvGetMetrics(t *testing.T) { - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } fFwv := &FileFWVee{em: em} if rcv := fFwv.GetMetrics(); !reflect.DeepEqual(rcv, fFwv.em) { @@ -171,7 +173,10 @@ func TestFileFwvExportEvent(t *testing.T) { filterS := engine.NewFilterS(cfg, nil, newDM) byteBuff := new(bytes.Buffer) csvNW := csv.NewWriter(byteBuff) - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } fFwv := &FileFWVee{ cfg: cfg.EEsCfg().Exporters[0], cgrCfg: cfg, @@ -204,7 +209,10 @@ func TestFileFwvExportEventWriteError(t *testing.T) { newDM := engine.NewDataManager(newIDb, cfg.CacheCfg(), nil) filterS := engine.NewFilterS(cfg, nil, newDM) byteBuff := new(bytes.Buffer) - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } fFwv := &FileFWVee{ cfg: cfg.EEsCfg().Exporters[0], cgrCfg: cfg, diff --git a/ees/httpjsonmap_test.go b/ees/httpjsonmap_test.go index c876014e3..d9d16a70c 100644 --- a/ees/httpjsonmap_test.go +++ b/ees/httpjsonmap_test.go @@ -32,7 +32,10 @@ import ( ) func TestHttpJsonMapGetMetrics(t *testing.T) { - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } httpEE := &HTTPjsonMapEE{ em: em, } diff --git a/ees/httppost_test.go b/ees/httppost_test.go index 06d2e3013..b8669ffbf 100644 --- a/ees/httppost_test.go +++ b/ees/httppost_test.go @@ -33,7 +33,10 @@ import ( ) func TestHttpPostGetMetrics(t *testing.T) { - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } httpPost := &HTTPPostEE{ em: em, } diff --git a/ees/nats_test.go b/ees/nats_test.go index 049dd711a..6b932abdb 100644 --- a/ees/nats_test.go +++ b/ees/nats_test.go @@ -43,7 +43,10 @@ func TestNewNatsEE(t *testing.T) { } nodeID := "node_id1" connTimeout := 2 * time.Second - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } exp := new(NatsEE) exp.cfg = cfg @@ -87,7 +90,10 @@ func TestParseOpt(t *testing.T) { opts := &config.EventExporterOpts{} nodeID := "node_id1" connTimeout := 2 * time.Second - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } pstr, err := NewNatsEE(cfg, nodeID, connTimeout, em) if err != nil { t.Error(err) @@ -121,7 +127,10 @@ func TestParseOptJetStream(t *testing.T) { } nodeID := "node_id1" connTimeout := 2 * time.Second - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } pstr, err := NewNatsEE(cfg, nodeID, connTimeout, em) if err != nil { t.Error(err) @@ -158,7 +167,10 @@ func TestParseOptSubject(t *testing.T) { }} nodeID := "node_id1" connTimeout := 2 * time.Second - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } pstr, err := NewNatsEE(cfg, nodeID, connTimeout, em) if err != nil { t.Error(err) diff --git a/ees/rpc_test.go b/ees/rpc_test.go index d8812b9b4..83e102eb2 100644 --- a/ees/rpc_test.go +++ b/ees/rpc_test.go @@ -31,7 +31,10 @@ import ( func TestNewRpcEE(t *testing.T) { eeSCfg := config.NewDefaultCGRConfig().EEsCfg().ExporterCfg(utils.MetaDefault) - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } connMgr := engine.NewConnManager(config.NewDefaultCGRConfig(), make(map[string]chan birpc.ClientConnector)) rcv, err := NewRpcEE(eeSCfg, em, connMgr) @@ -101,7 +104,10 @@ func TestRPCCfg(t *testing.T) { func TestRPCConnect(t *testing.T) { eeSCfg := config.NewDefaultCGRConfig().EEsCfg().ExporterCfg(utils.MetaDefault) - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } connMgr := engine.NewConnManager(config.NewDefaultCGRConfig(), make(map[string]chan birpc.ClientConnector)) rpcEe, err := NewRpcEE(eeSCfg, em, connMgr) if err != nil { @@ -114,7 +120,10 @@ func TestRPCConnect(t *testing.T) { func TestRPCClose(t *testing.T) { eeSCfg := config.NewDefaultCGRConfig().EEsCfg().ExporterCfg(utils.MetaDefault) - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } connMgr := engine.NewConnManager(config.NewDefaultCGRConfig(), make(map[string]chan birpc.ClientConnector)) rpcEe, err := NewRpcEE(eeSCfg, em, connMgr) if err != nil { @@ -149,7 +158,10 @@ func TestRPCGetMetrics(t *testing.T) { func TestRPCPrepareMap(t *testing.T) { eeSCfg := config.NewDefaultCGRConfig().EEsCfg().ExporterCfg(utils.MetaDefault) - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } connMgr := engine.NewConnManager(config.NewDefaultCGRConfig(), make(map[string]chan birpc.ClientConnector)) rpcEe, err := NewRpcEE(eeSCfg, em, connMgr) if err != nil { diff --git a/ees/sql_test.go b/ees/sql_test.go index ffe911857..8c5e7a44a 100644 --- a/ees/sql_test.go +++ b/ees/sql_test.go @@ -22,7 +22,6 @@ import ( "fmt" "reflect" "testing" - "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" @@ -33,7 +32,10 @@ import ( ) func TestSqlGetMetrics(t *testing.T) { - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } sqlEe := &SQLEe{ em: em, } diff --git a/ees/virtualee_test.go b/ees/virtualee_test.go index 5b2463386..8e3147cf8 100644 --- a/ees/virtualee_test.go +++ b/ees/virtualee_test.go @@ -21,7 +21,6 @@ package ees import ( "reflect" "testing" - "time" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" @@ -29,7 +28,10 @@ import ( ) func TestVirtualEeGetMetrics(t *testing.T) { - em := utils.NewExporterMetrics("", time.Local) + em, err := utils.NewExporterMetrics("", "Local") + if err != nil { + t.Fatal(err) + } vEe := &VirtualEE{ em: em, } diff --git a/utils/exportermetrics.go b/utils/exportermetrics.go index ade0fc90b..d8f5041dc 100644 --- a/utils/exportermetrics.go +++ b/utils/exportermetrics.go @@ -19,6 +19,7 @@ along with this program. If not, see package utils import ( + "fmt" "sync" "time" @@ -36,7 +37,11 @@ type ExporterMetrics struct { // NewExporterMetrics creates metrics with optional automatic reset. // schedule is a cron expression for reset timing (empty to disable). -func NewExporterMetrics(schedule string, loc *time.Location) *ExporterMetrics { +func NewExporterMetrics(schedule, timezone string) (*ExporterMetrics, error) { + loc, err := time.LoadLocation(timezone) + if err != nil { + return nil, err + } m := &ExporterMetrics{ loc: loc, } @@ -44,12 +49,15 @@ func NewExporterMetrics(schedule string, loc *time.Location) *ExporterMetrics { if schedule != "" { m.cron = cron.New() - m.cron.AddFunc(schedule, func() { + if _, err := m.cron.AddFunc(schedule, func() { m.Reset() - }) + }); err != nil { + // Only fails if schedule is an invalid cron expression. + return nil, fmt.Errorf("invalid cron expr %q: %v", schedule, err) + } m.cron.Start() } - return m + return m, nil } // Reset immediately clears all metrics and resets them to initial values.