diff --git a/apis/cores_it_test.go b/apis/cores_it_test.go
index 32bd9d2a2..1049d6a14 100644
--- a/apis/cores_it_test.go
+++ b/apis/cores_it_test.go
@@ -21,11 +21,15 @@ along with this program. If not, see
package apis
import (
+ "os"
+ "os/exec"
"path"
"testing"
+ "time"
"github.com/cgrates/birpc"
"github.com/cgrates/birpc/context"
+ "github.com/cgrates/birpc/jsonrpc"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
@@ -34,20 +38,32 @@ import (
var (
coreItCfgPath string
coreItDirPath string
+ argPath string
coreItCfg *config.CGRConfig
coreItBiRPC *birpc.Client
coreItTests = []func(t *testing.T){
testCoreItLoadConfig,
testCoreItInitDataDb,
testCoreItInitStorDb,
+ testCoreItStartEngineByExecWithCPUProfiling,
+ testCoreItRpcConn,
+ testCoreItStartCPUProfilingErrorAlreadyStarted,
+ testCoreItSleep,
+ testCoreItStopCPUProfiling,
+ testCoreItKillEngine,
testCoreItStartEngine,
testCoreItRpcConn,
+ testCoreItStopCPUProfilingBeforeStart,
+ testCoreItStartCPUProfiling,
+ testCoreItSleep,
+ testCoreItStopCPUProfiling,
testCoreItStatus,
testCoreItKillEngine,
}
)
func TestCoreItTests(t *testing.T) {
+ argPath = "/tmp/cpu.prof"
switch *dbType {
case utils.MetaInternal:
coreItDirPath = "all2"
@@ -83,6 +99,27 @@ func testCoreItInitStorDb(t *testing.T) {
}
}
+func testCoreItStartEngineByExecWithCPUProfiling(t *testing.T) {
+ engine := exec.Command("cgr-engine", "-config_path", coreItCfgPath, "-cpuprof_dir", "/tmp")
+ if err := engine.Start(); err != nil {
+ t.Error(err)
+ }
+ fib := utils.Fib()
+ var connected bool
+ for i := 0; i < 200; i++ {
+ time.Sleep(time.Duration(fib()) * time.Millisecond)
+ if _, err := jsonrpc.Dial(utils.TCP, coreItCfg.ListenCfg().RPCJSONListen); err != nil {
+ t.Log(err)
+ } else {
+ connected = true
+ break
+ }
+ }
+ if !connected {
+ t.Errorf("engine did not open port <%s>", coreItCfg.ListenCfg().RPCJSONListen)
+ }
+}
+
func testCoreItStartEngine(t *testing.T) {
if _, err := engine.StartEngine(coreItCfgPath, *waitRater); err != nil {
t.Fatal(err)
@@ -96,6 +133,74 @@ func testCoreItRpcConn(t *testing.T) {
}
}
+func testCoreItStartCPUProfilingErrorAlreadyStarted(t *testing.T) {
+ var reply string
+ expectedErr := "CPU profiling already started"
+ if err := coreItBiRPC.Call(context.Background(), utils.CoreSv1StartCPUProfiling,
+ argPath, &reply); err == nil || err.Error() != expectedErr {
+ t.Errorf("Expected %+v, received %+v", expectedErr, err)
+ }
+}
+
+func testCoreItSleep(t *testing.T) {
+ args := &utils.DurationArgs{
+ Duration: 500 * time.Millisecond,
+ }
+ var reply string
+ if err := coreItBiRPC.Call(context.Background(), utils.CoreSv1Sleep,
+ args, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.OK {
+ t.Errorf("Unexpected reply returned")
+ }
+}
+
+func testCoreItStopCPUProfiling(t *testing.T) {
+ var reply string
+ if err := coreItBiRPC.Call(context.Background(), utils.CoreSv1StopCPUProfiling,
+ utils.EmptyString, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.OK {
+ t.Errorf("Unexpected reply returned")
+ }
+ file, err := os.Open(argPath)
+ if err != nil {
+ t.Error(err)
+ }
+ defer file.Close()
+
+ //compare the size
+ size, err := file.Stat()
+ if err != nil {
+ t.Error(err)
+ } else if size.Size() < int64(415) {
+ t.Errorf("Size of CPUProfile %v is lower that expected", size.Size())
+ }
+ //after we checked that CPUProfile was made successfully, can delete it
+ if err := os.Remove(argPath); err != nil {
+ t.Error(err)
+ }
+}
+
+func testCoreItStopCPUProfilingBeforeStart(t *testing.T) {
+ var reply string
+ expectedErr := " cannot stop because CPUProfiling is not active"
+ if err := coreItBiRPC.Call(context.Background(), utils.CoreSv1StopCPUProfiling,
+ utils.EmptyString, &reply); err == nil || err.Error() != expectedErr {
+ t.Errorf("Expected %+q, received %+q", expectedErr, err)
+ }
+}
+
+func testCoreItStartCPUProfiling(t *testing.T) {
+ var reply string
+ if err := coreItBiRPC.Call(context.Background(), utils.CoreSv1StartCPUProfiling,
+ argPath, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.OK {
+ t.Errorf("Unexpected reply returned")
+ }
+}
+
func testCoreItStatus(t *testing.T) {
args := &utils.TenantIDWithAPIOpts{}
var reply map[string]interface{}
diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go
index d8244fad2..0fc67d5e7 100644
--- a/cmd/cgr-engine/cgr-engine.go
+++ b/cmd/cgr-engine/cgr-engine.go
@@ -303,21 +303,6 @@ func memProfiling(memProfDir string, interval time.Duration, nrFiles int, shdWg
}
}
-func startCPUProfiling(cpuProfDir string) (f io.WriteCloser, err error) {
- cpuPath := path.Join(cpuProfDir, utils.CpuPathCgr)
- if f, err = os.Create(cpuPath); err != nil {
- utils.Logger.Crit(fmt.Sprintf("could not create cpu profile file: %s", err))
- return
- }
- pprof.StartCPUProfile(f)
- return
-}
-
-func stopCPUProfiling(f io.Closer) {
- pprof.StopCPUProfile()
- f.Close()
-}
-
func singnalHandler(shdWg *sync.WaitGroup, shdChan *utils.SyncedChan) {
shutdownSignal := make(chan os.Signal, 1)
reloadSignal := make(chan os.Signal, 1)
@@ -628,7 +613,7 @@ func main() {
}
// init CoreSv1
- coreS := services.NewCoreService(cfg, caps, server, internalCoreSv1Chan, anz, srvDep, shdChan)
+ coreS := services.NewCoreService(cfg, caps, server, internalCoreSv1Chan, anz, cpuProfileFile, srvDep, shdChan)
shdWg.Add(1)
if err := coreS.Start(); err != nil {
fmt.Println(err)
diff --git a/services/cores.go b/services/cores.go
index 83105754b..d6fcbd0d1 100644
--- a/services/cores.go
+++ b/services/cores.go
@@ -33,10 +33,11 @@ import (
// NewCoreService returns the Core Service
func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, server *cores.Server,
- internalCoreSChan chan birpc.ClientConnector, anz *AnalyzerService,
+ internalCoreSChan chan birpc.ClientConnector, anz *AnalyzerService, file io.Closer,
srvDep map[string]*sync.WaitGroup, shdEngine *utils.SyncedChan) *CoreService {
return &CoreService{
connChan: internalCoreSChan,
+ fileCpu: file,
cfg: cfg,
caps: caps,
server: server,
diff --git a/utils/consts.go b/utils/consts.go
index f35c217bd..4397b2ab1 100644
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -1291,11 +1291,13 @@ const (
)
const (
- CoreS = "CoreS"
- CoreSv1 = "CoreSv1"
- CoreSv1Status = "CoreSv1.Status"
- CoreSv1Ping = "CoreSv1.Ping"
- CoreSv1Sleep = "CoreSv1.Sleep"
+ CoreS = "CoreS"
+ CoreSv1 = "CoreSv1"
+ CoreSv1Status = "CoreSv1.Status"
+ CoreSv1Ping = "CoreSv1.Ping"
+ CoreSv1Sleep = "CoreSv1.Sleep"
+ CoreSv1StartCPUProfiling = "CoreSv1.StartCPUProfiling"
+ CoreSv1StopCPUProfiling = "CoreSv1.StopCPUProfiling"
)
// RouteS APIs