Skip to content

Commit

Permalink
feat: add support for colorful output (#13)
Browse files Browse the repository at this point in the history
1. Supports colorful output(that not in json format).

2. Add flag `-C/--output.condense` for condensing output and disable colorful.
  It is generally suitable for output to a file to avoid recording color characters(like `^[[35m`).

3. The log fields order is changed from random to the following order: `level`, `time`, `msg`.

Fixes #13.
  • Loading branch information
windvalley committed Jan 6, 2022
1 parent 1871425 commit 9bc0fef
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 37 deletions.
18 changes: 16 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.3.0]

### Added

- Supports colorful output(that not in json format). For details at [#13](https://github.com/windvalley/gossh/issues/13).

- Add flag `-C/--output.condense` for condensing output and disable colorful.
It is generally suitable for output to a file to avoid recording color characters(like `^[[35m`).

### Changed

- The log fields order is changed from random to the following order: `level`, `time`, `msg`.

## [1.2.1]

### Fixed

- Fix bug that output in json format by flag '-j/--output.json' not correct [#12](https://github.com/windvalley/gossh/issues/12)
- Fix bug that output in json format by flag `-j/--output.json` not correct [#12](https://github.com/windvalley/gossh/issues/12)

## [1.2.0]

### Added

- Add `$PWD/.gossh.yaml` as the default configuration file with higher priority than `$HOME/.gossh.yaml`.

- Add `-L/--hosts.list` for subcommand `command`,`script`,`push`. Just outputs a list of target hosts, and does not do anything else.
- Add `-L/--hosts.list` for subcommand `command`,`script`,`push`.
Just outputs a list of target hosts, and does not do anything else.

### Changed

Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ It can efficiently execute commands, execute a shell script, transfer files and
Timeout for executing commands or a shell script on each remote host or pushing files/dirs to each remote host.
Timeout for the current `gossh` task.

- Supports printing the execution results of `gossh` to a file or screen or a file and screen at the same time. Supports json format output. Supports printing debug information. Supports silent output.
- Supports printing output to a file or screen or a file and screen at the same time.
Supports json format output, colorful output, verbose(debug) output, and silent output.

- High-performance and high-concurrency. You can specify number of concurrent connections (default `1`).

Expand Down Expand Up @@ -113,6 +114,7 @@ Flags:
-H, --hosts.file string file containing target hosts (format: one host/pattern per line)
-L, --hosts.list outputs a list of target hosts, and does not do anything else
-P, --hosts.port int port of target hosts (default 22)
-C, --output.condense condense output and disable color
-o, --output.file string file to which messages are output
-j, --output.json output messages in json format
-q, --output.quiet do not output messages to screen (except error messages)
Expand Down Expand Up @@ -169,7 +171,7 @@ Output:
```text
...

time=2021-12-22 23:06:50 level=info msg=success count: 936, failed count: 0, elapsed: 6.30s
level=INFO time=2021-12-22 23:06:50 msg=success count: 936, failed count: 0, elapsed: 6.30s

real 0m6.316s
user 0m13.529s
Expand Down
1 change: 1 addition & 0 deletions internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func initLogger() {
config.Output.JSON,
config.Output.Verbose,
config.Output.Quiet,
config.Output.Condense,
)
}

Expand Down
28 changes: 16 additions & 12 deletions internal/pkg/configflags/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,30 @@ package configflags
import "github.com/spf13/pflag"

const (
flagOutputFile = "output.file"
flagOutputJSON = "output.json"
flagOutputQuite = "output.quiet"
flagOutputVerbose = "output.verbose"
flagOutputFile = "output.file"
flagOutputJSON = "output.json"
flagOutputQuite = "output.quiet"
flagOutputVerbose = "output.verbose"
flagOutputCondense = "output.condense"
)

// Output ...
type Output struct {
File string `json:"file" mapstructure:"file"`
JSON bool `json:"json" mapstructure:"json"`
Quiet bool `json:"quiet" mapstructure:"quiet"`
Verbose bool `json:"verbose" mapstructure:"verbose"`
File string `json:"file" mapstructure:"file"`
JSON bool `json:"json" mapstructure:"json"`
Quiet bool `json:"quiet" mapstructure:"quiet"`
Verbose bool `json:"verbose" mapstructure:"verbose"`
Condense bool `json:"condense" mapstructure:"condense"`
}

// NewOutput ...
func NewOutput() *Output {
return &Output{
File: "",
JSON: false,
Quiet: false,
Verbose: false,
File: "",
JSON: false,
Quiet: false,
Verbose: false,
Condense: false,
}
}

Expand All @@ -56,6 +59,7 @@ func (o *Output) AddFlagsTo(flags *pflag.FlagSet) {
flags.BoolVarP(&o.Quiet, flagOutputQuite, "q", o.Quiet,
"do not output messages to screen (except error messages)")
flags.BoolVarP(&o.Verbose, flagOutputVerbose, "v", o.Verbose, "show debug messages")
flags.BoolVarP(&o.Condense, flagOutputCondense, "C", o.Condense, "condense output and disable color")
}

// Complete ...
Expand Down
7 changes: 4 additions & 3 deletions internal/pkg/sshtask/sshtask.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,14 +606,15 @@ func getPasswordFromPrompt() string {
var passwordByte []byte
passwordByte, err := term.ReadPassword(0)
if err != nil {
util.CheckErr(fmt.Sprintf("get password from terminal failed: %s", err))
err = fmt.Errorf("get password from terminal failed: %s", err)
}
util.CheckErr(err)

password := string(passwordByte)

log.Debugf("Auth: read password of the login user from terminal prompt")

fmt.Println("")

log.Debugf("Auth: read password of the login user from terminal prompt")

return password
}
70 changes: 53 additions & 17 deletions pkg/log/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,21 @@ import (
"encoding/json"
"fmt"
"time"

"github.com/fatih/color"
)

const timeFormat = "2006-01-02 15:04:05"

type colorType int

const (
green colorType = iota
yellow
red
magenta
)

// entry ...
type entry struct {
Logger *Logger
Expand All @@ -43,7 +54,7 @@ func newEntry(logger *Logger) *entry {
}
}

func (e *entry) print() {
func (e *entry) print(colorName colorType) {
e.Data["time"] = time.Now().Format(timeFormat)

entry := ""
Expand All @@ -52,16 +63,41 @@ func (e *entry) print() {
entry = string(entryByte)
} else {
if len(e.Data) <= 3 {
for k, v := range e.Data {
entry += fmt.Sprintf("%v=%v ", k, v)
}
} else {
entry = fmt.Sprintf("%q,%q,%q,\"%s\"",
e.Data["hostname"],
e.Data["status"],
entry = fmt.Sprintf(
"level=%s time=%s msg=%s",
e.Data["level"],
e.Data["time"],
e.Data["output"],
e.Data["msg"],
)
} else {
if e.Logger.Condense {
entry = fmt.Sprintf("%q,%q,%q,\"%s\"",
e.Data["hostname"],
e.Data["status"],
e.Data["time"],
e.Data["output"],
)
} else {
entry = fmt.Sprintf("%s | %s | %s >>\n%s\n",
e.Data["hostname"],
e.Data["time"],
e.Data["status"],
e.Data["output"],
)
}
}

if !e.Logger.Condense {
switch colorName {
case green:
entry = color.GreenString(entry)
case red:
entry = color.RedString(entry)
case yellow:
entry = color.YellowString(entry)
case magenta:
entry = color.MagentaString(entry)
}
}
}

Expand All @@ -74,40 +110,40 @@ func (e *entry) Debugf(format string, args ...interface{}) {
return
}

e.Data["level"] = "debug"
e.Data["level"] = "DEBUG"

msg := fmt.Sprintf(format, args...)
e.Data["msg"] = msg

e.print()
e.print(magenta)
}

// Infof ...
func (e *entry) Infof(format string, args ...interface{}) {
e.Data["level"] = "info"
e.Data["level"] = "INFO"

msg := fmt.Sprintf(format, args...)
e.Data["msg"] = msg

e.print()
e.print(green)
}

// Warnf ...
func (e *entry) Warnf(format string, args ...interface{}) {
e.Data["level"] = "warn"
e.Data["level"] = "WARN"

msg := fmt.Sprintf(format, args...)
e.Data["msg"] = msg

e.print()
e.print(yellow)
}

// Errorf ...
func (e *entry) Errorf(format string, args ...interface{}) {
e.Data["level"] = "error"
e.Data["level"] = "ERROR"

msg := fmt.Sprintf(format, args...)
e.Data["msg"] = msg

e.print()
e.print(red)
}
6 changes: 5 additions & 1 deletion pkg/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var (
var std = New()

// Init log
func Init(logfile string, json, verbose, quiet bool) {
func Init(logfile string, json, verbose, quiet, condense bool) {
if verbose {
std.Verbose = true
}
Expand All @@ -51,6 +51,10 @@ func Init(logfile string, json, verbose, quiet bool) {
std.JSONFormat = true
}

if condense {
std.Condense = true
}

if logfile != "" {
//nolint:gomnd
file, err := os.OpenFile(logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
Expand Down
2 changes: 2 additions & 0 deletions pkg/log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Logger struct {
Out io.Writer
Verbose bool
JSONFormat bool
Condense bool
ExitFunc exitFunc
}

Expand All @@ -46,6 +47,7 @@ func New() *Logger {
Out: os.Stdout,
Verbose: false,
JSONFormat: false,
Condense: false,
ExitFunc: os.Exit,
}
}
Expand Down

0 comments on commit 9bc0fef

Please sign in to comment.