diff --git a/go.mod b/go.mod index 0c507a6..bb349ac 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect github.com/fatih/color v1.7.0 + github.com/hpcloud/tail v1.0.0 // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/mattn/go-colorable v0.1.4 // indirect github.com/mattn/go-isatty v0.0.11 // indirect @@ -15,4 +16,6 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/struCoder/pidusage v0.1.3 gopkg.in/alecthomas/kingpin.v2 v2.2.6 + gopkg.in/fsnotify.v1 v1.4.7 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect ) diff --git a/go.sum b/go.sum index cc31d3c..0db3941 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= @@ -39,5 +41,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/lib/cli/cli.go b/lib/cli/cli.go index 078c285..369c3a1 100644 --- a/lib/cli/cli.go +++ b/lib/cli/cli.go @@ -1,8 +1,12 @@ package cli import ( + "bufio" "fmt" + "github.com/hpcloud/tail" + "os" "strconv" + "sync" "time" "github.com/fatih/color" @@ -29,6 +33,69 @@ func InitCli(dsn string, timeout time.Duration) *Cli { } } +// Logs +// +// Logs will display the logs of a process. +// --follow will follow the logs. +func (cli *Cli) Logs(name string, follow bool) { + userDirectory, err := os.UserHomeDir() + if err != nil { + panic(err) + } + _, err = os.Stat(userDirectory + "/.pmgo/" + name) + if err != nil { + fmt.Println(fmt.Errorf("Process %s logs not found", name)) + } + if follow { + cli.followLogs(userDirectory, name) + } else { + cli.getLogs(userDirectory, name) + } +} + +func (cli *Cli) getLogs(userDirectory, name string) { + files := []string{ + fmt.Sprintf("%s/.pmgo/%s/%s.err", userDirectory, name, name), + fmt.Sprintf("%s/.pmgo/%s/%s.out", userDirectory, name, name), + } + for _, file := range files { + if _, err := os.Stat(file); err != nil { + fmt.Println(fmt.Errorf("Process %s logs not found", name)) + return + } + file, err := os.Open(file) + if err != nil { + panic(err) + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + fmt.Println(scanner.Text()) + } + } +} + +func (cli *Cli) followLogs(userDirectory, name string) { + files := []string{ + fmt.Sprintf("%s/.pmgo/%s/%s.err", userDirectory, name, name), + fmt.Sprintf("%s/.pmgo/%s/%s.out", userDirectory, name, name), + } + var wg sync.WaitGroup + for _, file := range files { + wg.Add(1) + go func(file string) { + t, err := tail.TailFile(file, tail.Config{Follow: true, ReOpen: true}) + if err != nil { + panic(err) + } + for line := range t.Lines { + fmt.Println(line.Text) + } + }(file) + } + wg.Wait() +} + // Save will save all previously saved processes onto a list. // Display an error in case there's any. func (cli *Cli) Save() { diff --git a/pmgo.go b/pmgo.go index 19e6340..3d01123 100644 --- a/pmgo.go +++ b/pmgo.go @@ -83,6 +83,10 @@ var ( info = app.Command("info", "Describe importance parameters of a process id") infoName = info.Arg("name", "process name").Required().String() + + logs = app.Command("logs", "Get logs of a process id") + logsName = logs.Arg("name", "process name").Required().String() + logsArgs = logs.Flag("follow", "follow logs").Bool() ) func main() { @@ -129,6 +133,9 @@ func main() { checkRemoteMasterServer() cli := cli.InitCli(*dns, timeout) cli.ProcInfo(*infoName) + case logs.FullCommand(): + cli := cli.InitCli(*dns, timeout) + cli.Logs(*logsName, *logsArgs) } }