Permalink
Browse files

Add verbose and extended-perfdata flags (#274)

* Add struct for OuputConfig and function to check for value in a string slice

* Add StringSliceFlag for format options

* Implement outputConfig

* Update manual

* Remove nagios_verbose. Now covered by format-options.
  • Loading branch information...
pysysops authored and aelsabbahy committed May 20, 2018
1 parent e6140f9 commit de7d3d8c37e234bdf9259748087c35a5e67ad9e6
@@ -49,6 +49,11 @@ func main() {
Usage: fmt.Sprintf("Format to output in, valid options: %s", outputs.Outputers()),
EnvVar: "GOSS_FMT",
},
cli.StringSliceFlag{
Name: "format-options, o",
Usage: fmt.Sprintf("Extra options passed to the formatter, valid options: %s", outputs.FormatOptions()),
EnvVar: "GOSS_FMT_OPTIONS",
},
cli.BoolFlag{
Name: "color",
Usage: "Force color on",
@@ -94,6 +99,11 @@ func main() {
Usage: fmt.Sprintf("Format to output in, valid options: %s", outputs.Outputers()),
EnvVar: "GOSS_FMT",
},
cli.StringSliceFlag{
Name: "format-options, o",
Usage: fmt.Sprintf("Extra options passed to the formatter, valid options: %s", outputs.FormatOptions()),
EnvVar: "GOSS_FMT_OPTIONS",
},
cli.DurationFlag{
Name: "cache,c",
Usage: "Time to cache the results",
@@ -282,10 +282,12 @@ $ curl localhost:8080/healthz
* `json_oneline` - Same as json, but oneliner
* `junit`
* `nagios` - Nagios/Sensu compatible output /w exit code 2 for failures.
* `nagios_verbose` - Nagios output with verbose failure output.
* `rspecish` **(default)** - Similar to rspec output
* `tap`
* `silent` - No output. Avoids exposing system information (e.g. when serving tests as a healthcheck endpoint).
* `--format-options`, `-o` (output format option)
* `perfdata` - Outputs Nagios "performance data". Applies to `nagios` output.
* `verbose` - Gives verbose output. Applies to `nagios` output.
* `--max-concurrent` - Max number of tests to run concurrently
* `--no-color` - Disable color
* `--color` - Force enable color
@@ -313,9 +315,13 @@ $ goss render | ssh remote-host 'goss -g - validate'
Total Duration: 0.002s
Count: 6, Failed: 0, Skipped: 0
```
$ goss validate --format nagios -o verbose -o perfdata
GOSS CRITICAL - Count: 76, Failed: 1, Skipped: 0, Duration: 1.009s|total=76 failed=1 skipped=0 duration=1.009s
Fail 1 - DNS: localhost: addrs: doesn't match, expect: [["127.0.0.1","::1"]] found: [["127.0.0.1"]]
$ echo $?
2
```
## Important note about goss file format
It is important to note that both YAML and JSON are formats that describe a nested data structure.
@@ -6,11 +6,14 @@ import (
"time"
"github.com/aelsabbahy/goss/resource"
"github.com/aelsabbahy/goss/util"
)
type Documentation struct{}
func (r Documentation) Output(w io.Writer, results <-chan []resource.TestResult, startTime time.Time) (exitCode int) {
func (r Documentation) Output(w io.Writer, results <-chan []resource.TestResult,
startTime time.Time, outConfig util.OutputConfig) (exitCode int) {
testCount := 0
var failedOrSkipped [][]resource.TestResult
var skipped, failed int
@@ -52,5 +55,5 @@ func (r Documentation) Output(w io.Writer, results <-chan []resource.TestResult,
}
func init() {
RegisterOutputer("documentation", &Documentation{})
RegisterOutputer("documentation", &Documentation{}, []string{})
}
@@ -7,12 +7,15 @@ import (
"time"
"github.com/aelsabbahy/goss/resource"
"github.com/aelsabbahy/goss/util"
"github.com/fatih/color"
)
type Json struct{}
func (r Json) Output(w io.Writer, results <-chan []resource.TestResult, startTime time.Time) (exitCode int) {
func (r Json) Output(w io.Writer, results <-chan []resource.TestResult,
startTime time.Time, outConfig util.OutputConfig) (exitCode int) {
color.NoColor = true
testCount := 0
failed := 0
@@ -52,7 +55,7 @@ func (r Json) Output(w io.Writer, results <-chan []resource.TestResult, startTim
}
func init() {
RegisterOutputer("json", &Json{})
RegisterOutputer("json", &Json{}, []string{})
}
func struct2map(i interface{}) map[string]interface{} {
@@ -7,12 +7,15 @@ import (
"time"
"github.com/aelsabbahy/goss/resource"
"github.com/aelsabbahy/goss/util"
"github.com/fatih/color"
)
type JsonOneline struct{}
func (r JsonOneline) Output(w io.Writer, results <-chan []resource.TestResult, startTime time.Time) (exitCode int) {
func (r JsonOneline) Output(w io.Writer, results <-chan []resource.TestResult,
startTime time.Time, outConfig util.OutputConfig) (exitCode int) {
color.NoColor = true
testCount := 0
failed := 0
@@ -52,5 +55,5 @@ func (r JsonOneline) Output(w io.Writer, results <-chan []resource.TestResult, s
}
func init() {
RegisterOutputer("json_oneline", &JsonOneline{})
RegisterOutputer("json_oneline", &JsonOneline{}, []string{})
}
@@ -9,12 +9,15 @@ import (
"time"
"github.com/aelsabbahy/goss/resource"
"github.com/aelsabbahy/goss/util"
"github.com/fatih/color"
)
type JUnit struct{}
func (r JUnit) Output(w io.Writer, results <-chan []resource.TestResult, startTime time.Time) (exitCode int) {
func (r JUnit) Output(w io.Writer, results <-chan []resource.TestResult,
startTime time.Time, outConfig util.OutputConfig) (exitCode int) {
color.NoColor = true
var testCount, failed, skipped int
@@ -75,7 +78,7 @@ func (r JUnit) Output(w io.Writer, results <-chan []resource.TestResult, startTi
}
func init() {
RegisterOutputer("junit", &JUnit{})
RegisterOutputer("junit", &JUnit{}, []string{})
}
func escapeString(str string) string {
@@ -3,19 +3,34 @@ package outputs
import (
"fmt"
"io"
"strconv"
"time"
"github.com/aelsabbahy/goss/resource"
"github.com/aelsabbahy/goss/util"
)
type Nagios struct{}
func (r Nagios) Output(w io.Writer, results <-chan []resource.TestResult, startTime time.Time) (exitCode int) {
func (r Nagios) Output(w io.Writer, results <-chan []resource.TestResult,
startTime time.Time, outConfig util.OutputConfig) (exitCode int) {
var testCount, failed, skipped int
var perfdata, verbose bool
perfdata = util.IsValueInList("perfdata", outConfig.FormatOptions)
verbose = util.IsValueInList("verbose", outConfig.FormatOptions)
var summary map[int]string
summary = make(map[int]string)
for resultGroup := range results {
for _, testResult := range resultGroup {
switch testResult.Result {
case resource.FAIL:
if util.IsValueInList("verbose", outConfig.FormatOptions) {
summary[failed] = "Fail " + strconv.Itoa(failed+1) + " - " + humanizeResult2(testResult) + "\n"
}
failed++
case resource.SKIP:
skipped++
@@ -26,13 +41,26 @@ func (r Nagios) Output(w io.Writer, results <-chan []resource.TestResult, startT
duration := time.Since(startTime)
if failed > 0 {
fmt.Fprintf(w, "GOSS CRITICAL - Count: %d, Failed: %d, Skipped: %d, Duration: %.3fs\n", testCount, failed, skipped, duration.Seconds())
fmt.Fprintf(w, "GOSS CRITICAL - Count: %d, Failed: %d, Skipped: %d, Duration: %.3fs", testCount, failed, skipped, duration.Seconds())
if perfdata {
fmt.Fprintf(w, "|total=%d failed=%d skipped=%d duration=%.3fs", testCount, failed, skipped, duration.Seconds())
}
fmt.Fprint(w, "\n")
if verbose {
for i := 0; i < failed; i++ {
fmt.Fprintf(w, "%s", summary[i])
}
}
return 2
}
fmt.Fprintf(w, "GOSS OK - Count: %d, Failed: %d, Skipped: %d, Duration: %.3fs\n", testCount, failed, skipped, duration.Seconds())
fmt.Fprintf(w, "GOSS OK - Count: %d, Failed: %d, Skipped: %d, Duration: %.3fs", testCount, failed, skipped, duration.Seconds())
if perfdata {
fmt.Fprintf(w, "|total=%d failed=%d skipped=%d duration=%.3fs", testCount, failed, skipped, duration.Seconds())
}
fmt.Fprint(w, "\n")
return 0
}
func init() {
RegisterOutputer("nagios", &Nagios{})
RegisterOutputer("nagios", &Nagios{}, []string{"perfdata", "verbose"})
}

This file was deleted.

Oops, something went wrong.
@@ -10,11 +10,12 @@ import (
"time"
"github.com/aelsabbahy/goss/resource"
"github.com/aelsabbahy/goss/util"
"github.com/fatih/color"
)
type Outputer interface {
Output(io.Writer, <-chan []resource.TestResult, time.Time) int
Output(io.Writer, <-chan []resource.TestResult, time.Time, util.OutputConfig) int
}
var green = color.New(color.FgGreen).SprintfFunc()
@@ -78,11 +79,12 @@ func humanizeResult2(r resource.TestResult) string {
// Copied from database/sql
var (
outputersMu sync.Mutex
outputers = make(map[string]Outputer)
outputersMu sync.Mutex
outputers = make(map[string]Outputer)
outputerFormatOptions = make(map[string][]string)
)
func RegisterOutputer(name string, outputer Outputer) {
func RegisterOutputer(name string, outputer Outputer, formatOptions []string) {
outputersMu.Lock()
defer outputersMu.Unlock()
@@ -93,6 +95,7 @@ func RegisterOutputer(name string, outputer Outputer) {
panic("goss: Register called twice for ouputer " + name)
}
outputers[name] = outputer
outputerFormatOptions[name] = formatOptions
}
// Outputers returns a sorted list of the names of the registered outputers.
@@ -107,6 +110,21 @@ func Outputers() []string {
return list
}
func FormatOptions() []string {
outputersMu.Lock()
defer outputersMu.Unlock()
var list []string
for _, formatOptions := range outputerFormatOptions {
for _, opt := range formatOptions {
if !(util.IsValueInList(opt, list)) {
list = append(list, opt)
}
}
}
sort.Strings(list)
return list
}
func GetOutputer(name string) Outputer {
if _, ok := outputers[name]; !ok {
fmt.Println("goss: Bad output format: " + name)
@@ -6,11 +6,14 @@ import (
"time"
"github.com/aelsabbahy/goss/resource"
"github.com/aelsabbahy/goss/util"
)
type Rspecish struct{}
func (r Rspecish) Output(w io.Writer, results <-chan []resource.TestResult, startTime time.Time) (exitCode int) {
func (r Rspecish) Output(w io.Writer, results <-chan []resource.TestResult,
startTime time.Time, outConfig util.OutputConfig) (exitCode int) {
testCount := 0
var failedOrSkipped [][]resource.TestResult
var skipped, failed int
@@ -47,5 +50,5 @@ func (r Rspecish) Output(w io.Writer, results <-chan []resource.TestResult, star
}
func init() {
RegisterOutputer("rspecish", &Rspecish{})
RegisterOutputer("rspecish", &Rspecish{}, []string{})
}
@@ -5,11 +5,14 @@ import (
"time"
"github.com/aelsabbahy/goss/resource"
"github.com/aelsabbahy/goss/util"
)
type Silent struct{}
func (r Silent) Output(w io.Writer, results <-chan []resource.TestResult, startTime time.Time) (exitCode int) {
func (r Silent) Output(w io.Writer, results <-chan []resource.TestResult,
startTime time.Time, outConfig util.OutputConfig) (exitCode int) {
var failed int
for resultGroup := range results {
for _, testResult := range resultGroup {
@@ -27,5 +30,5 @@ func (r Silent) Output(w io.Writer, results <-chan []resource.TestResult, startT
}
func init() {
RegisterOutputer("silent", &Silent{})
RegisterOutputer("silent", &Silent{}, []string{})
}
@@ -7,11 +7,14 @@ import (
"time"
"github.com/aelsabbahy/goss/resource"
"github.com/aelsabbahy/goss/util"
)
type Tap struct{}
func (r Tap) Output(w io.Writer, results <-chan []resource.TestResult, startTime time.Time) (exitCode int) {
func (r Tap) Output(w io.Writer, results <-chan []resource.TestResult,
startTime time.Time, outConfig util.OutputConfig) (exitCode int) {
testCount := 0
failed := 0
@@ -49,5 +52,5 @@ func (r Tap) Output(w io.Writer, results <-chan []resource.TestResult, startTime
}
func init() {
RegisterOutputer("tap", &Tap{})
RegisterOutputer("tap", &Tap{}, []string{})
}
Oops, something went wrong.

0 comments on commit de7d3d8

Please sign in to comment.