Skip to content

Commit

Permalink
Add new command to show logs of detached instances
Browse files Browse the repository at this point in the history
This change adds a new command, `show logs`, to show log entries of detached
application instances.

Closes #123
  • Loading branch information
David Pinheiro committed Sep 13, 2020
1 parent 65e5ee2 commit 0d814f6
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 38 deletions.
55 changes: 39 additions & 16 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/davrodpin/mole/fsutils"
"github.com/gofrs/uuid"
"github.com/hpcloud/tail"
)

const (
Expand All @@ -31,7 +32,7 @@ type DetachedInstance struct {
}

// NewDetachedInstance returns a new instance of DetachedInstance, making sure
// the instance directory is created.
// the application instance directory is created.
func NewDetachedInstance(id string) (*DetachedInstance, error) {
instanceDir, err := fsutils.Dir()
if err != nil {
Expand All @@ -49,21 +50,22 @@ func NewDetachedInstance(id string) (*DetachedInstance, error) {
home := filepath.Join(instanceDir, id)

if _, err := os.Stat(home); os.IsNotExist(err) {
err := os.Mkdir(home, 0755)
err := os.MkdirAll(home, 0755)
if err != nil {
return nil, err
}
}

lfp, err := GetPidFileLocation(id)
pfl, err := GetPidFileLocation(id)
if err != nil {
return nil, err
}

if _, err := os.Stat(lfp); !os.IsNotExist(err) {
data, err := ioutil.ReadFile(lfp)
if _, err = os.Stat(pfl); !os.IsNotExist(err) {
_, err = os.Stat(pfl)
data, err := ioutil.ReadFile(pfl)
if err != nil {
return nil, fmt.Errorf("something went wrong while opening pid file %s: %v", lfp, err)
return nil, fmt.Errorf("something went wrong while reading from pid file %s: %v", pfl, err)
}

pid := string(data)
Expand All @@ -74,24 +76,28 @@ func NewDetachedInstance(id string) (*DetachedInstance, error) {

}

lf, err := os.Create(lfp)
if err != nil {
return nil, fmt.Errorf("could not create log file for application instance %s: %v", id, err)
}
defer lf.Close()

pfp := filepath.Join(home, InstancePidFile)
pf, err := os.Create(pfp)
pf, err := os.Create(pfl)
if err != nil {
return nil, fmt.Errorf("could not create pid file for application instance %s: %v", id, err)
}
defer pf.Close()
pf.WriteString(strconv.Itoa(os.Getpid()))

lfl, err := GetLogFileLocation(id)
if err != nil {
return nil, err
}

lf, err := os.Create(lfl)
if err != nil {
return nil, fmt.Errorf("could not create log file for application instance %s: %v", id, err)
}
defer lf.Close()

return &DetachedInstance{
Id: id,
LogFile: lfp,
PidFile: pfp,
LogFile: lfl,
PidFile: pfl,
}, nil
}

Expand Down Expand Up @@ -120,3 +126,20 @@ func GetLogFileLocation(id string) (string, error) {

return lfp, nil
}

func ShowLogs(id string, follow bool) error {
lfl, err := GetLogFileLocation(id)
if err != nil {
return err
}

t, err := tail.TailFile(lfl, tail.Config{Follow: follow})
if err != nil {
return err
}
for line := range t.Lines {
fmt.Println(line.Text)
}

return nil
}
104 changes: 104 additions & 0 deletions app/app_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package app_test

import (
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/davrodpin/mole/app"
)

var (
// home is a temporary directory that acts as the user home directory.
// It is used on most tests to validates files created by Mole and their
// contents.
home string
)

func TestDetachedInstanceFileLocations(t *testing.T) {
id := "TestDetachedInstanceFileLocations"

di, err := app.NewDetachedInstance(id)
if err != nil {
t.Errorf("error creating a new detached instance: %v", err)
}

if _, err := os.Stat(di.LogFile); os.IsNotExist(err) {
t.Errorf("log file does not exist: %v", err)
}

if _, err := os.Stat(di.PidFile); os.IsNotExist(err) {
t.Errorf("pid file does not exist: %v", err)
}

lfl, err := app.GetLogFileLocation(id)
if err != nil {
t.Errorf("error retrieving log file location: %v", err)
}

if _, err := os.Stat(lfl); os.IsNotExist(err) {
t.Errorf("log file does not exist: %v", err)
}

}

func TestDetachedInstanceGeneratedId(t *testing.T) {

di, err := app.NewDetachedInstance("")
if err != nil {
t.Errorf("error creating a new detached instance: %v", err)
}

if di.Id == "" {
t.Errorf("detached instance id is empty")
}
}

func TestDetachedInstanceAlreadyRunning(t *testing.T) {
id := "TestDetachedInstanceAlreadyRunning"

os.MkdirAll(filepath.Join(home, ".mole", id), 0755)
pidFileLocation := filepath.Join(home, ".mole", id, app.InstancePidFile)
ioutil.WriteFile(pidFileLocation, []byte("1234"), 0644)

_, err := app.NewDetachedInstance(id)

if err == nil {
t.Errorf("error expected but got nil")
}

}

func TestShowLogs(t *testing.T) {
id := "TestDetachedInstanceAlreadyRunning"

os.MkdirAll(filepath.Join(home, ".mole", id), 0755)
logFileLocation := filepath.Join(home, ".mole", id, app.InstanceLogFile)
ioutil.WriteFile(logFileLocation, []byte("first log message\nsecond log message\nthird log message\n"), 0644)

err := app.ShowLogs(id, false)

if err != nil {
t.Errorf("error showing logs: %v", err)
}

}

func TestMain(m *testing.M) {
var err error

home, err = ioutil.TempDir("", "mole")
if err != nil {
os.Exit(1)
}

os.Setenv("HOME", home)
os.Setenv("USERPROFILE", home)

code := m.Run()

os.RemoveAll(home)

os.Exit(code)
}
25 changes: 3 additions & 22 deletions cmd/show_logs.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package cmd

import (
"bufio"
"fmt"
"os"

"github.com/davrodpin/mole/app"
Expand All @@ -12,6 +10,7 @@ import (
)

var (
follow bool
showLogsCmd = &cobra.Command{
Use: "logs [name]",
Short: "Shows log messages of a detached running application instance",
Expand All @@ -24,36 +23,18 @@ var (
return nil
},
Run: func(cmd *cobra.Command, arg []string) {
lfl, err := app.GetLogFileLocation(id)
if err != nil {
log.WithError(err).Error("error stopping detached mole instance")
os.Exit(1)
}

file, err := os.Open(lfl)
err := app.ShowLogs(id, follow)
if err != nil {
log.WithError(err).WithFields(log.Fields{
"id": id,
}).Error("error opening log file")
os.Exit(1)
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}

if err := scanner.Err(); err != nil {
log.WithError(err).WithFields(log.Fields{
"id": id,
}).Error("error reading log file")
os.Exit(1)
}
},
}
)

func init() {
showLogsCmd.Flags().BoolVarP(&follow, "follow", "f", false, "output appended data as the file grows")
showCmd.AddCommand(showLogsCmd)
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/BurntSushi/toml v0.3.1
github.com/awnumar/memguard v0.17.1
github.com/gofrs/uuid v3.2.0+incompatible
github.com/hpcloud/tail v1.0.0
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
Expand All @@ -19,4 +20,6 @@ require (
github.com/spf13/viper v1.3.2
github.com/stretchr/testify v1.3.0 // indirect
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
Expand Down Expand Up @@ -115,6 +117,10 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

0 comments on commit 0d814f6

Please sign in to comment.