PIng command json output (#141)

* cmd_ping now respects --json

* ctrl-c doesn't print the cancel message for sq ping

* changelog update
This commit is contained in:
Neil O'Toole 2023-01-01 06:00:07 +00:00 committed by GitHub
parent 5d799a8820
commit 82dfd1c703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 99 additions and 17 deletions

View File

@ -5,13 +5,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Added
- `sq ping` now respects `--json` flag.
### Fixed
- Improved handling of file paths on Windows.
## [v0.23.0] - 2022-12-31
### Added
- `sq ls` now respects `--json flag`.
- `sq rm` now respects `--json flag`.
- `sq add` now respects `--json flag`.
- `sq ls` now respects `--json` flag.
- `sq rm` now respects `--json` flag.
- `sq add` now respects `--json` flag.
- CI pipeline now verifies install packages after publish.
### Changed

View File

@ -593,6 +593,7 @@ func newWriters(log lg.Log, cmd *cobra.Command, defaults config.Defaults, out, e
w.srcw = jsonw.NewSourceWriter(out2, fm)
w.errw = jsonw.NewErrorWriter(log, errOut2, fm)
w.versionw = jsonw.NewVersionWriter(out2, fm)
w.pingw = jsonw.NewPingWriter(out2, fm)
case config.FormatTable:
// Table is the base format, already set above, no need to do anything.
@ -819,7 +820,7 @@ func printError(rc *RunContext, err error) {
switch {
default:
case errors.Is(err, context.Canceled):
err = errz.New("stopped")
err = errz.New("canceled")
case errors.Is(err, context.DeadlineExceeded):
err = errz.New("timeout")
}

View File

@ -46,6 +46,7 @@ The exit code is 1 if ping fails for any of the sources.`,
cmd.Flags().BoolP(flagTable, flagTableShort, false, flagTableUsage)
cmd.Flags().BoolP(flagCSV, flagCSVShort, false, flagCSVUsage)
cmd.Flags().BoolP(flagTSV, flagTSVShort, false, flagTSVUsage)
cmd.Flags().BoolP(flagJSON, flagJSONShort, false, flagJSONUsage)
cmd.Flags().Duration(flagPingTimeout, time.Second*10, flagPingTimeoutUsage)
cmd.Flags().BoolP(flagPingAll, flagPingAllShort, false, flagPingAllUsage)
@ -98,21 +99,28 @@ func execPing(cmd *cobra.Command, args []string) error {
rc.Log.Debugf("Using ping timeout value: %s", timeout)
return pingSources(cmd.Context(), rc.Log, rc.registry, srcs, rc.writers.pingw, timeout)
err := pingSources(cmd.Context(), rc.Log, rc.registry, srcs, rc.writers.pingw, timeout)
if errors.Is(err, context.Canceled) {
// It's common to cancel "sq ping". We don't want to print the cancel message.
return errNoMsg
}
return err
}
// pingSources pings each of the sources in srcs, and prints results
// to w. If any error occurs pinging any of srcs, that error is printed
// inline as part of the ping results, and an errNoMsg is returned.
//
// NOTE: This ping code has an ancient lineage, in that it was written
//
// originally laid down before context.Context was a thing. Thus,
// the entire thing could probably be rewritten for simplicity.
// NOTE: This ping code has an ancient lineage, in that it was
// originally laid down before context.Context was a thing. Thus,
// the entire thing could probably be rewritten for simplicity.
func pingSources(ctx context.Context, log lg.Log, dp driver.Provider, srcs []*source.Source, w output.PingWriter,
timeout time.Duration,
) error {
w.Open(srcs)
if err := w.Open(srcs); err != nil {
return err
}
defer log.WarnIfFuncError(w.Close)
resultCh := make(chan pingResult, len(srcs))
@ -147,7 +155,7 @@ func pingSources(ctx context.Context, log lg.Log, dp driver.Provider, srcs []*so
pingErrExists = true
}
w.Result(result.src, result.duration, result.err)
log.WarnIfError(w.Result(result.src, result.duration, result.err))
}
// If there's at least one error, we return the

View File

@ -27,11 +27,12 @@ type pingWriter struct {
}
// Open implements output.PingWriter.
func (p *pingWriter) Open(srcs []*source.Source) {
func (p *pingWriter) Open(srcs []*source.Source) error {
return nil
}
// Result implements output.PingWriter.
func (p *pingWriter) Result(src *source.Source, d time.Duration, err error) {
func (p *pingWriter) Result(src *source.Source, d time.Duration, err error) error {
rec := make([]string, 3)
rec[0] = src.Handle
rec[1] = d.Truncate(time.Millisecond).String()
@ -47,6 +48,7 @@ func (p *pingWriter) Result(src *source.Source, d time.Duration, err error) {
_ = p.csvw.Write(rec)
p.csvw.Flush()
return nil
}
// Close implements output.PingWriter.

View File

@ -0,0 +1,59 @@
package jsonw
import (
"io"
"time"
"github.com/neilotoole/sq/cli/output"
"github.com/neilotoole/sq/cli/output/jsonw/internal"
jcolorenc "github.com/neilotoole/sq/cli/output/jsonw/internal/jcolorenc"
"github.com/neilotoole/sq/libsq/core/errz"
"github.com/neilotoole/sq/libsq/source"
)
var _ output.PingWriter = (*pingWriter)(nil)
// NewPingWriter returns JSON impl of output.PingWriter.
func NewPingWriter(out io.Writer, fm *output.Formatting) output.PingWriter {
return &pingWriter{out: out, fm: fm}
}
type pingWriter struct {
out io.Writer
fm *output.Formatting
}
// Open implements output.PingWriter.
func (p pingWriter) Open(srcs []*source.Source) error {
return nil
}
// Result implements output.PingWriter.
func (p pingWriter) Result(src *source.Source, d time.Duration, err error) error {
r := struct {
*source.Source
Pong bool `json:"pong"`
Duration time.Duration `json:"duration"`
Error string `json:"error,omitempty"`
}{
Source: src,
Pong: err == nil,
Duration: d,
}
if err != nil {
r.Error = err.Error()
}
enc := jcolorenc.NewEncoder(p.out)
enc.SetColors(internal.NewColors(p.fm))
enc.SetEscapeHTML(false)
enc.SetIndent("", " ")
return errz.Err(enc.Encode(r))
}
// Close implements output.PingWriter.
func (p pingWriter) Close() error {
return nil
}

View File

@ -28,15 +28,16 @@ type PingWriter struct {
handleWidthMax int
}
func (w *PingWriter) Open(srcs []*source.Source) {
func (w *PingWriter) Open(srcs []*source.Source) error {
for _, src := range srcs {
if len(src.Handle) > w.handleWidthMax {
w.handleWidthMax = len(src.Handle)
}
}
return nil
}
func (w *PingWriter) Result(src *source.Source, d time.Duration, err error) {
func (w *PingWriter) Result(src *source.Source, d time.Duration, err error) error {
w.fm.Number.Fprintf(w.out, "%-"+strconv.Itoa(w.handleWidthMax)+"s", src.Handle)
fmt.Fprintf(w.out, "%10s ", d.Truncate(time.Millisecond).String())
@ -60,6 +61,7 @@ func (w *PingWriter) Result(src *source.Source, d time.Duration, err error) {
}
fmt.Fprintf(w.out, "\n")
return nil
}
func (w *PingWriter) Close() error {

View File

@ -74,12 +74,12 @@ type ErrorWriter interface {
// PingWriter writes ping results.
type PingWriter interface {
// Open opens the writer to write the supplied sources.
Open(srcs []*source.Source)
Open(srcs []*source.Source) error
// Result prints a ping result. The ping succeeded if
// err is nil. If err is context.DeadlineExceeded, the d
// arg will be the timeout value.
Result(src *source.Source, d time.Duration, err error)
Result(src *source.Source, d time.Duration, err error) error
// Close is called after all results have been received.
Close() error