diff --git a/DEVELOP.md b/DEVELOP.md index d87d323..06176a6 100644 --- a/DEVELOP.md +++ b/DEVELOP.md @@ -11,8 +11,8 @@ sh init_dev.sh ## 测试开发 ```shell -sudo PMON2_CONF=config/config-dev.yml ./bin/pmond -sudo PMON2_CONF=config/config-dev.yml ./bin/pmon2 exec bin/test +sudo PMON2_DEBUG=true PMON2_CONF=config/config-dev.yml ./bin/pmond +sudo PMON2_DEBUG=true PMON2_CONF=config/config-dev.yml ./bin/pmon2 exec bin/test ``` 因为 `pmon2` 启动进程使用的是fork/exec,所以需要sudo或root级别权限。 diff --git a/README.md b/README.md index 3d7ce07..560c4cb 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ Go官方一直没有提供任何进程管理工具,对于 `Go` 服务的部署 ```bash # CentOS6 -sudo yum install -y https://github.com/ntt360/pmon2/releases/download/v1.12.0/pmon2-1.12.0-1.el6.x86_64.rpm +sudo yum install -y https://github.com/ntt360/pmon2/releases/download/v1.12.0/pmon2-1.12.1-1.el6.x86_64.rpm # CentOS7 -sudo yum install -y https://github.com/ntt360/pmon2/releases/download/v1.12.0/pmon2-1.12.0-1.el7.x86_64.rpm +sudo yum install -y https://github.com/ntt360/pmon2/releases/download/v1.12.0/pmon2-1.12.1-1.el7.x86_64.rpm # CentOS8 -sudo yum install -y https://github.com/ntt360/pmon2/releases/download/v1.12.0/pmon2-1.12.0-1.el8.x86_64.rpm +sudo yum install -y https://github.com/ntt360/pmon2/releases/download/v1.12.0/pmon2-1.12.1-1.el8.x86_64.rpm ``` :exclamation::exclamation: **注意:** :exclamation::exclamation: @@ -98,6 +98,9 @@ sudo pmon2 run [./二进制文件名] [参数1] [参数2] ... // 进程运行日志,不配置则使用默认路径:/var/log/pmon2/ --log -l +// 仅自定义日志目录,优先级低于 --log +--log_dir -d + // 进程自定义参数,多个参数以空格分割 --args -a "-arg1=val1 -arg2=val2" diff --git a/app/executor/executor.go b/app/executor/executor.go index 7c84b29..5fad519 100644 --- a/app/executor/executor.go +++ b/app/executor/executor.go @@ -11,8 +11,8 @@ import ( "syscall" ) -func Exec(processFile, customLogFile, name, extArgs string, user *user.User, autoRestart bool) (*model.Process, error) { - logPath, err := getLogPath(customLogFile, crypto.Crc32Hash(processFile)) +func Exec(processFile, customLogFile, name, extArgs string, user *user.User, autoRestart bool, logDir string) (*model.Process, error) { + logPath, err := getLogPath(customLogFile, crypto.Crc32Hash(processFile), logDir) if err != nil { return nil, err } diff --git a/app/executor/process_log.go b/app/executor/process_log.go index e02b2de..2561ba3 100644 --- a/app/executor/process_log.go +++ b/app/executor/process_log.go @@ -10,8 +10,13 @@ import ( const logSuffix = ".log" -func getLogPath(customLogFile string, hash string) (string, error) { - prjDir := strings.TrimRight(app.Config.GetLogsDir(), "/") +func getLogPath(customLogFile string, hash string, logDir string) (string, error) { + if len(logDir) <= 0 { + app.Log.Debugf("custom log dir: %s \n", logDir) + logDir = app.Config.GetLogsDir() + } + + prjDir := strings.TrimRight(logDir, "/") if len(customLogFile) <= 0 { _, err := os.Stat(prjDir) if os.IsNotExist(err) { @@ -23,6 +28,8 @@ func getLogPath(customLogFile string, hash string) (string, error) { customLogFile = prjDir + "/" + hash + logSuffix } + app.Log.Debugf("log file is: %s \n", customLogFile) + return customLogFile, nil } diff --git a/app/god/monitor.go b/app/god/monitor.go index 634135c..eac719c 100644 --- a/app/god/monitor.go +++ b/app/god/monitor.go @@ -91,7 +91,6 @@ func checkFork(process model.Process) bool { } func restartProcess(p model.Process) error { - //fmt.Printf("Monitor: try get process (%d) status \n", p.Pid) _, err := os.Stat(fmt.Sprintf("/proc/%d/status", p.Pid)) if err == nil { // process already running //fmt.Printf("Monitor: process (%d) already running \n", p.Pid) @@ -100,7 +99,6 @@ func restartProcess(p model.Process) error { // proc status file not exit if os.IsNotExist(err) && (p.Status == model.StatusRunning || p.Status == model.StatusFailed) { - //fmt.Printf("Monitor: process not exist %s \n", p.Status) if checkFork(p) { return nil } @@ -114,8 +112,7 @@ func restartProcess(p model.Process) error { return nil } - //fmt.Printf("try to restart process %d \n", p.Pid) - _, err := process2.TryStart(p) + _, err := process2.TryStart(p, "") if err != nil { return err } diff --git a/app/model/exec_flags.go b/app/model/exec_flags.go index 6430dca..06da2f9 100644 --- a/app/model/exec_flags.go +++ b/app/model/exec_flags.go @@ -5,12 +5,13 @@ import "encoding/json" type ExecFlags struct { User string `json:"user"` Log string `json:"log"` + LogDir string `json:"log_dir"` NoAutoRestart bool `json:"no_auto_restart"` Args string `json:"args"` Name string `json:"name"` } -func (ExecFlags) Parse(jsonStr string) (*ExecFlags, error) { +func (e *ExecFlags) Parse(jsonStr string) (*ExecFlags, error) { var m ExecFlags err := json.Unmarshal([]byte(jsonStr), &m) if err != nil { diff --git a/app/svc/process/process.go b/app/svc/process/process.go index f0a08ce..aca06d7 100644 --- a/app/svc/process/process.go +++ b/app/svc/process/process.go @@ -11,16 +11,6 @@ import ( "strconv" ) -func FindByProcessFile(pFile string) *model.Process { - var rel model.Process - err := app.Db().First(&rel, "process_file = ?", pFile).Error - if err != nil { - return nil - } - - return &rel -} - func IsRunning(pid int) bool { _, err := os.Stat(fmt.Sprintf("/proc/%d/status", pid)) if err != nil { @@ -30,7 +20,7 @@ func IsRunning(pid int) bool { return true } -func TryStop(forced bool, p *model.Process ) error { +func TryStop(forced bool, p *model.Process) error { var cmd *exec.Cmd if forced { cmd = exec.Command("kill", "-9", strconv.Itoa(p.Pid)) @@ -48,7 +38,7 @@ func TryStop(forced bool, p *model.Process ) error { return app.Db().Save(p).Error } -func TryStart(m model.Process) ([]string, error) { +func TryStart(m model.Process, flags string) ([]string, error) { var flagsModel = model.ExecFlags{ User: m.Username, Log: m.Log, @@ -57,6 +47,25 @@ func TryStart(m model.Process) ([]string, error) { Name: m.Name, } + if len(flags) > 0 { + app.Log.Debugf("start with flags: %s \n", flags) + execFlags := model.ExecFlags{} + curFlag, err := execFlags.Parse(flags) + if err != nil { + return nil, err + } + + if len(curFlag.Log) > 0 { + flagsModel.Log = curFlag.Log + } + + // log dir + if len(curFlag.LogDir) > 0 && len(curFlag.Log) == 0 { + flagsModel.LogDir = curFlag.LogDir + flagsModel.Log = "" + } + } + data, err := proxy.RunProcess([]string{"restart", m.ProcessFile, flagsModel.Json()}) if err != nil { return nil, err diff --git a/client/cmd/exec/exec.go b/client/cmd/exec/exec.go index a35a11e..5ccc6dd 100644 --- a/client/cmd/exec/exec.go +++ b/client/cmd/exec/exec.go @@ -29,6 +29,7 @@ func init() { Cmd.Flags().StringVarP(&flag.Log, "log", "l", "", "the process stdout log") Cmd.Flags().StringVarP(&flag.Args, "args", "a", "", "the process extra arguments") Cmd.Flags().StringVar(&flag.Name, "name", "", "run process name") + Cmd.Flags().StringVarP(&flag.LogDir, "log_dir", "d", "", "the process stdout log dir") } func cmdRun(args []string, flags string) { diff --git a/client/cmd/restart/restart.go b/client/cmd/restart/restart.go index e503907..fe1c88d 100644 --- a/client/cmd/restart/restart.go +++ b/client/cmd/restart/restart.go @@ -10,15 +10,22 @@ import ( "os" ) +var flag model.ExecFlags + var Cmd = &cobra.Command{ Use: "restart", Short: "restart some process by id or name", Run: func(cmd *cobra.Command, args []string) { - cmdRun(args) + cmdRun(args, flag.Json()) }, } -func cmdRun(args []string) { +func init() { + Cmd.Flags().StringVarP(&flag.LogDir, "log_dir", "d", "", "the process stdout log dir") + Cmd.Flags().StringVarP(&flag.Log, "log", "l", "", "the process stdout log") +} + +func cmdRun(args []string, flags string) { if len(args) == 0 { app.Log.Fatal("please input restart process id or name") } @@ -36,7 +43,7 @@ func cmdRun(args []string) { } } - rel, err := process.TryStart(m) + rel, err := process.TryStart(m, flags) if err != nil { if len(os.Getenv("PMON2_DEBUG")) > 0 { app.Log.Fatalf("%+v", err) diff --git a/client/cmd/start/start.go b/client/cmd/start/start.go index 6c4b7cf..1233aa3 100644 --- a/client/cmd/start/start.go +++ b/client/cmd/start/start.go @@ -10,15 +10,22 @@ import ( "os" ) +var flag model.ExecFlags + var Cmd = &cobra.Command{ Use: "start", Short: "start some process by id or name", Run: func(cmd *cobra.Command, args []string) { - cmdRun(args) + cmdRun(args, flag.Json()) }, } -func cmdRun(args []string) { +func init() { + Cmd.Flags().StringVarP(&flag.LogDir, "log_dir", "d", "", "the process stdout log dir") + Cmd.Flags().StringVarP(&flag.Log, "log", "l", "", "the process stdout log") +} + +func cmdRun(args []string, flags string) { if len(args) == 0 { app.Log.Fatal("please input start process id or name") } @@ -39,7 +46,7 @@ func cmdRun(args []string) { return } - rel, err := process.TryStart(m) + rel, err := process.TryStart(m, flags) if err != nil { if len(os.Getenv("PMON2_DEBUG")) > 0 { app.Log.Fatalf("%+v", err) diff --git a/client/proxy/proxy.go b/client/proxy/proxy.go index b6f38ef..7b14ed7 100644 --- a/client/proxy/proxy.go +++ b/client/proxy/proxy.go @@ -30,7 +30,8 @@ func RunProcess(args []string) ([]byte, error) { var output string - flagModel, err := model.ExecFlags{}.Parse(args[2]) + flags := model.ExecFlags{} + flagModel, err := flags.Parse(args[2]) if err != nil { return nil, errors.WithStack(err) } diff --git a/client/worker/restart.go b/client/worker/restart.go index edba531..afa134b 100644 --- a/client/worker/restart.go +++ b/client/worker/restart.go @@ -21,6 +21,11 @@ func Restart(pFile string, flags *model.ExecFlags) (string, error) { m.Log = cstLog } + // if reset log dir + if len(flags.LogDir) > 0 && len(flags.Log) == 0 { + m.Log = "" + } + cstName := flags.Name if len(cstName) > 0 && cstName != m.Name { m.Name = cstName @@ -42,7 +47,7 @@ func Restart(pFile string, flags *model.ExecFlags) (string, error) { return "", err } - process, err := executor.Exec(m.ProcessFile, m.Log, m.Name, m.Args, runUser, !flags.NoAutoRestart) + process, err := executor.Exec(m.ProcessFile, m.Log, m.Name, m.Args, runUser, !flags.NoAutoRestart, flags.LogDir) if err != nil { return "", err } diff --git a/client/worker/start.go b/client/worker/start.go index ea63c88..d261a82 100644 --- a/client/worker/start.go +++ b/client/worker/start.go @@ -34,7 +34,7 @@ func Start(processFile string, flags *model.ExecFlags) (string, error) { return "", errors.Errorf("process name: %s already exist, please set other name by --name", name) } // start process - process, err := executor.Exec(processFile, flags.Log, name, flags.Args, runUser, !flags.NoAutoRestart) + process, err := executor.Exec(processFile, flags.Log, name, flags.Args, runUser, !flags.NoAutoRestart, flags.LogDir) if err != nil { return "", err } diff --git a/cmd/pmond/pmond.go b/cmd/pmond/pmond.go index 17d44ef..26932e3 100644 --- a/cmd/pmond/pmond.go +++ b/cmd/pmond/pmond.go @@ -14,6 +14,8 @@ func main() { log.Fatal(err) } + log.Printf("pmon2 daemon is running! \n") + // start monitor process file god.NewMonitor() } diff --git a/init_dev.sh b/init_dev.sh index 15d9df1..089c813 100755 --- a/init_dev.sh +++ b/init_dev.sh @@ -8,7 +8,7 @@ set -e rootDir=$(cd "$(dirname "$0")"; pwd) -rm -rf "$rootDir/config/config-dev.yml" +sudo rm -rf "$rootDir/config/config-dev.yml" "$rootDir/tmp" # 写配置 cd "config" @@ -30,6 +30,7 @@ fi mkdir -p "$logs" # build go bin +go mod tidy go build -o bin/pmon2 cmd/pmon2/pmon2.go go build -o bin/pmond cmd/pmond/pmond.go # `bin/test` 进程是用于测试模拟的业务进程,开发也可以测试自己的业务进程。