diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 82d6499d2..5de47ab60 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -21,7 +21,6 @@ package main import ( "flag" "fmt" - "io" "log" "os" "os/signal" @@ -354,7 +353,7 @@ func main() { go singnalHandler(shdWg, shdChan) var cS *cores.CoreService - var cpuProf io.Closer + var cpuProf *os.File if *cpuProfDir != utils.EmptyString { cpuPath := filepath.Join(*cpuProfDir, utils.CpuPathCgr) cpuProf, err = cores.StartCPUProfiling(cpuPath) @@ -371,7 +370,7 @@ func main() { } pprof.StopCPUProfile() if err := cpuProf.Close(); err != nil { - log.Printf("could not close file %q: %v", cpuProf.(*os.File).Name(), err) + log.Print(err) } }() } diff --git a/cores/core.go b/cores/core.go index c6abbaba9..ba2360e50 100644 --- a/cores/core.go +++ b/cores/core.go @@ -21,7 +21,6 @@ package cores import ( "errors" "fmt" - "io" "os" "path" "path/filepath" @@ -36,7 +35,7 @@ import ( "github.com/cgrates/cgrates/utils" ) -func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, fileCPU io.Closer, stopChan chan struct{}, +func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, fileCPU *os.File, stopChan chan struct{}, shdWg *sync.WaitGroup, shdChan *utils.SyncedChan) *CoreService { var st *engine.CapsStats if caps.IsLimited() && cfg.CoreSCfg().CapsStatsInterval != 0 { @@ -63,7 +62,7 @@ type CoreService struct { stopMemProf chan struct{} // signal end of memory profiling fileCPUMux sync.Mutex - fileCPU io.Closer + fileCPU *os.File caps *engine.Caps } @@ -76,27 +75,38 @@ func (cS *CoreService) Shutdown() { } // StartCPUProfiling starts CPU profiling and saves the profile to the specified path. -func (cS *CoreService) StartCPUProfiling(path string) (err error) { +func (cS *CoreService) StartCPUProfiling(path string) error { if path == utils.EmptyString { return utils.NewErrMandatoryIeMissing("DirPath") } cS.fileCPUMux.Lock() defer cS.fileCPUMux.Unlock() - cS.fileCPU, err = StartCPUProfiling(path) - return + + if cS.fileCPU != nil { + // Check if the profiling is already active by calling Stat() on the file handle. + // If Stat() returns nil, it means profiling is already active. + if _, err := cS.fileCPU.Stat(); err == nil { + return errors.New("start CPU profiling: already started") + } + } + file, err := StartCPUProfiling(path) + if err != nil { + return err + } + cS.fileCPU = file + return nil } // StartCPUProfiling creates a file and passes it to pprof.StartCPUProfile. It returns the file -// as an io.Closer to be able to close it later when stopping the CPU profiling. -func StartCPUProfiling(path string) (io.Closer, error) { +// to be able to verify the status of profiling and close it after profiling is stopped. +func StartCPUProfiling(path string) (*os.File, error) { f, err := os.Create(path) if err != nil { return nil, fmt.Errorf("could not create CPU profile: %v", err) } if err := pprof.StartCPUProfile(f); err != nil { if err := f.Close(); err != nil { - utils.Logger.Warning(fmt.Sprintf( - "<%s> could not close file %q: %v", utils.CoreS, f.Name(), err)) + utils.Logger.Warning(fmt.Sprintf("<%s> %v", utils.CoreS, err)) } return nil, fmt.Errorf("could not start CPU profile: %v", err) } diff --git a/services/cores.go b/services/cores.go index 2de91e012..8dc88d527 100644 --- a/services/cores.go +++ b/services/cores.go @@ -20,7 +20,7 @@ package services import ( "fmt" - "io" + "os" "sync" "github.com/cgrates/birpc" @@ -33,7 +33,7 @@ import ( // NewCoreService returns the Core Service func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, server *cores.Server, internalCoreSChan chan birpc.ClientConnector, anz *AnalyzerService, - fileCpu io.Closer, shdWg *sync.WaitGroup, shdChan *utils.SyncedChan, + fileCPU *os.File, shdWg *sync.WaitGroup, shdChan *utils.SyncedChan, srvDep map[string]*sync.WaitGroup) *CoreService { return &CoreService{ shdChan: shdChan, @@ -41,7 +41,7 @@ func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, server *cores.Serv connChan: internalCoreSChan, cfg: cfg, caps: caps, - fileCpu: fileCpu, + fileCPU: fileCPU, server: server, anz: anz, srvDep: srvDep, @@ -57,7 +57,7 @@ type CoreService struct { stopChan chan struct{} shdWg *sync.WaitGroup shdChan *utils.SyncedChan - fileCpu io.Closer + fileCPU *os.File cS *cores.CoreService connChan chan birpc.ClientConnector anz *AnalyzerService @@ -74,7 +74,7 @@ func (cS *CoreService) Start() error { defer cS.Unlock() utils.Logger.Info(fmt.Sprintf("<%s> starting <%s> subsystem", utils.CoreS, utils.CoreS)) cS.stopChan = make(chan struct{}) - cS.cS = cores.NewCoreService(cS.cfg, cS.caps, cS.fileCpu, cS.stopChan, cS.shdWg, cS.shdChan) + cS.cS = cores.NewCoreService(cS.cfg, cS.caps, cS.fileCPU, cS.stopChan, cS.shdWg, cS.shdChan) srv, err := engine.NewServiceWithName(cS.cS, utils.CoreS, true) if err != nil { return err