Skip to content

Commit

Permalink
Improve CLI output format
Browse files Browse the repository at this point in the history
  • Loading branch information
yottahmd committed Apr 26, 2022
1 parent d50d844 commit f2b233a
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 66 deletions.
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.17
require (
github.com/google/uuid v1.3.0
github.com/imdario/mergo v0.3.12
github.com/jedib0t/go-pretty/v6 v6.3.1
github.com/mitchellh/mapstructure v1.5.0
github.com/stretchr/testify v1.7.1
github.com/urfave/cli/v2 v2.4.5
Expand All @@ -14,8 +15,11 @@ require (

require (
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
13 changes: 12 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jedib0t/go-pretty/v6 v6.3.1 h1:aOXiD9oqiuLH8btPQW6SfgtQN5zwhyfzZls8a6sPJ/I=
github.com/jedib0t/go-pretty/v6 v6.3.1/go.mod h1:FMkOpgGD3EZ91cW8g/96RfxoV7bdeJyzXPYgz1L1ln0=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/urfave/cli/v2 v2.4.5 h1:AWCiaqBc+38MxX6nJfjRQyyd2Gq50sOan+AEyv/vFhM=
github.com/urfave/cli/v2 v2.4.5/go.mod h1:oDzoM7pVwz6wHn5ogWgFUU1s4VJayeQS+aEZDqXIEJs=
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c h1:uHnKXcvx6SNkuwC+nrzxkJ+TpPwZOtumbhWrrOYN5YA=
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
18 changes: 10 additions & 8 deletions internal/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,21 +268,22 @@ func (a *Agent) run() error {
defer close(done)
go func() {
for node := range done {
a.dbWriter.Write(a.Status())
a.reporter.ReportStep(a.scheduler, a.graph, a.Job, node)
status := a.Status()
a.dbWriter.Write(status)
a.reporter.ReportStep(a.Job, status, node)
}
}()

lastErr := a.scheduler.Schedule(a.graph, done)
status := a.scheduler.Status(a.graph)
status := a.Status()

log.Println("schedule finished.")
if err := a.dbWriter.Write(a.Status()); err != nil {
log.Printf("failed to write status. %s", err)
}

a.reporter.Report(status, a.graph.Nodes(), lastErr)
if err := a.reporter.ReportMail(status, a.graph, lastErr, a.Job); err != nil {
a.reporter.ReportSummary(status, lastErr)
if err := a.reporter.ReportMail(a.Job, status); err != nil {
log.Printf("failed to send mail. %s", err)
}

Expand All @@ -294,15 +295,16 @@ func (a *Agent) dryRun() error {
defer close(done)
go func() {
for node := range done {
a.reporter.ReportStep(a.scheduler, a.graph, a.Job, node)
status := a.Status()
a.reporter.ReportStep(a.Job, status, node)
}
}()

log.Printf("***** Starting DRY-RUN *****")

lastErr := a.scheduler.Schedule(a.graph, done)
status := a.scheduler.Status(a.graph)
a.reporter.Report(status, a.graph.Nodes(), lastErr)
status := a.Status()
a.reporter.ReportSummary(status, lastErr)

log.Printf("***** Finished DRY-RUN *****")

Expand Down
107 changes: 67 additions & 40 deletions internal/reporter/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import (
"log"
"strings"

"github.com/jedib0t/go-pretty/v6/table"
"github.com/yohamta/jobctl/internal/config"
"github.com/yohamta/jobctl/internal/mail"
"github.com/yohamta/jobctl/internal/models"
"github.com/yohamta/jobctl/internal/scheduler"
"github.com/yohamta/jobctl/internal/utils"
)

type Reporter struct {
Expand All @@ -26,39 +27,43 @@ func New(config *Config) *Reporter {
}
}

func (rp *Reporter) ReportStep(sc *scheduler.Scheduler, g *scheduler.ExecutionGraph,
cfg *config.Config, node *scheduler.Node) error {
status := node.ReadStatus()
if status != scheduler.NodeStatus_None {
log.Printf("%s %s", node.Name, status)
func (rp *Reporter) ReportStep(cfg *config.Config, status *models.Status, node *scheduler.Node) error {
st := node.ReadStatus()
if st != scheduler.NodeStatus_None {
log.Printf("%s %s", node.Name, status.StatusText)
}
if status == scheduler.NodeStatus_Error && node.MailOnError {
return rp.sendError(cfg, sc.Status(g), g.Nodes())
if st == scheduler.NodeStatus_Error && node.MailOnError {
return rp.sendError(cfg, status)
}
return nil
}

func (rp *Reporter) Report(status scheduler.SchedulerStatus,
nodes []*scheduler.Node, err error) {
log.Printf(toText(status, nodes, err))
func (rp *Reporter) ReportSummary(status *models.Status, err error) {
var buf bytes.Buffer
buf.Write([]byte("\n"))
buf.Write([]byte("Summary ->\n"))
buf.Write([]byte(renderSummary(status, err)))
buf.Write([]byte("\n"))
buf.Write([]byte("Details ->\n"))
buf.Write([]byte(renderTable(status.Nodes)))
log.Printf(buf.String())
}

func (rp *Reporter) ReportMail(status scheduler.SchedulerStatus,
g *scheduler.ExecutionGraph, err error, cfg *config.Config) error {
if err != nil && status != scheduler.SchedulerStatus_Cancel && cfg.MailOn.Failure {
return rp.sendError(cfg, status, g.Nodes())
func (rp *Reporter) ReportMail(cfg *config.Config, status *models.Status) error {
if (status.Status != scheduler.SchedulerStatus_Error &&
status.Status != scheduler.SchedulerStatus_Cancel) && cfg.MailOn.Failure {
return rp.sendError(cfg, status)
} else if cfg.MailOn.Success {
return rp.sendInfo(cfg, status, g.Nodes())
return rp.sendInfo(cfg, status)
}
return nil
}

func (rp *Reporter) sendInfo(cfg *config.Config,
status scheduler.SchedulerStatus, nodes []*scheduler.Node) error {
func (rp *Reporter) sendInfo(cfg *config.Config, status *models.Status) error {
mailConfig := cfg.InfoMail
jobName := cfg.Name
subject := fmt.Sprintf("%s %s (%s)", mailConfig.Prefix, jobName, status)
body := toHtml(status, nodes)
body := renderHTML(status.Nodes)

return rp.Mailer.SendMail(
cfg.InfoMail.From,
Expand All @@ -68,12 +73,11 @@ func (rp *Reporter) sendInfo(cfg *config.Config,
)
}

func (rp *Reporter) sendError(cfg *config.Config,
status scheduler.SchedulerStatus, nodes []*scheduler.Node) error {
func (rp *Reporter) sendError(cfg *config.Config, status *models.Status) error {
mailConfig := cfg.ErrorMail
jobName := cfg.Name
subject := fmt.Sprintf("%s %s (%s)", mailConfig.Prefix, jobName, status)
body := toHtml(status, nodes)
body := renderHTML(status.Nodes)

return rp.Mailer.SendMail(
cfg.ErrorMail.From,
Expand All @@ -83,19 +87,46 @@ func (rp *Reporter) sendError(cfg *config.Config,
)
}

func toText(status scheduler.SchedulerStatus, nodes []*scheduler.Node, err error) string {
vals := []string{}
vals = append(vals, "[Result]")
for _, n := range nodes {
vals = append(vals, fmt.Sprintf("\t%s", n.Report()))
}
func renderSummary(status *models.Status, err error) string {
t := table.NewWriter()
var errText = ""
if err != nil {
vals = append(vals, fmt.Sprintf("\tLast Error=%s", err.Error()))
errText = err.Error()
}
t.AppendHeader(table.Row{"Name", "Started At", "Finished At", "Status", "Params", "Error"})
t.AppendRow(table.Row{
status.Name,
status.StartedAt,
status.FinishedAt,
status.Status,
status.Params,
errText,
})
return t.Render()
}

func renderTable(nodes []*models.Node) string {
t := table.NewWriter()
t.AppendHeader(table.Row{"#", "Step", "Started At", "Finished At", "Status", "Command", "Error"})
for i, n := range nodes {
var command = n.Command
if n.Args != nil {
command = strings.Join([]string{n.Command, strings.Join(n.Args, " ")}, " ")
}
t.AppendRow(table.Row{
fmt.Sprintf("%d", i+1),
n.Name,
n.StartedAt,
n.FinishedAt,
n.StatusText,
command,
n.Error,
})
}
return strings.Join(vals, "\n")
return t.Render()
}

func toHtml(status scheduler.SchedulerStatus, list []*scheduler.Node) string {
func renderHTML(nodes []*models.Node) string {
var buffer bytes.Buffer
addValFunc := func(val string) {
buffer.WriteString(
Expand Down Expand Up @@ -125,17 +156,13 @@ func toHtml(status scheduler.SchedulerStatus, list []*scheduler.Node) string {
fmt.Sprintf("<td align=\"center\" style=\"padding: 10px; %s\">%s</td>",
style, status))
}
for _, n := range list {
for _, n := range nodes {
buffer.WriteString("<tr>")
addValFunc(n.Name)
addValFunc(utils.FormatTime(n.StartedAt))
addValFunc(utils.FormatTime(n.FinishedAt))
addStatusFunc(n.ReadStatus())
if n.Error != nil {
addValFunc(n.Error.Error())
} else {
addValFunc("-")
}
addValFunc(n.StartedAt)
addValFunc(n.FinishedAt)
addStatusFunc(n.Status)
addValFunc(n.Error)
buffer.WriteString("</tr>")
}
buffer.WriteString("</table>")
Expand Down
16 changes: 0 additions & 16 deletions internal/scheduler/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -99,21 +98,6 @@ func (n *Node) ReadStatus() NodeStatus {
return ret
}

func (n *Node) Report() string {
vals := []string{}
vals = append(vals, fmt.Sprintf("Step: %s", n.Name))
vals = append(vals, fmt.Sprintf("Status: %s", n.ReadStatus()))
cmd := n.Command
if len(n.Args) > 0 {
cmd += " " + strings.Join(n.Args, " ")
}
vals = append(vals, fmt.Sprintf("Command: %s", cmd))
if n.Error != nil {
vals = append(vals, fmt.Sprintf("Error: %s", n.Error))
}
return strings.Join(vals, "\t")
}

func (n *Node) updateStatus(status NodeStatus) {
n.mu.Lock()
defer n.mu.Unlock()
Expand Down

0 comments on commit f2b233a

Please sign in to comment.