From d2c93df5bee42181c988d43e9c66108e3e62d164 Mon Sep 17 00:00:00 2001 From: Jorin Vogel Date: Fri, 10 Feb 2017 19:37:15 +0100 Subject: [PATCH] Allow 'd' as day unit for -range flag. Closes #7. --- flags/duration.go | 37 +++++++++++++++++++++++++++++++ flags/duration_test.go | 49 ++++++++++++++++++++++++++++++++++++++++++ main.go | 2 +- 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 flags/duration.go create mode 100644 flags/duration_test.go diff --git a/flags/duration.go b/flags/duration.go new file mode 100644 index 0000000..e56da02 --- /dev/null +++ b/flags/duration.go @@ -0,0 +1,37 @@ +package flags + +import ( + "flag" + "regexp" + "strconv" + "time" +) + +type durationValue time.Duration + +var matchDay = regexp.MustCompile("[-+]?[0-9]*(\\.[0-9]*)?d") + +func (d *durationValue) Set(s string) error { + if is := matchDay.FindStringIndex(s); is != nil { + days, err := strconv.ParseFloat(s[is[0]:is[1]-1], 64) + if err != nil { + return err + } + s = s[:is[0]] + s[is[1]:] + strconv.FormatFloat(days*24, 'f', 6, 64) + "h" + } + v, err := time.ParseDuration(s) + *d = durationValue(v) + return err +} + +func (d *durationValue) String() string { + return (*time.Duration)(d).String() +} + +// Duration defines a flag for time.Duration values. +// It works the same way as flag.Duration except that it als parses "XXd" values as days. +func Duration(name string, value time.Duration, usage string) *time.Duration { + t := &value + flag.Var((*durationValue)(t), name, usage) + return t +} diff --git a/flags/duration_test.go b/flags/duration_test.go new file mode 100644 index 0000000..c238cd0 --- /dev/null +++ b/flags/duration_test.go @@ -0,0 +1,49 @@ +package flags + +import ( + "testing" + "time" +) + +func TestDuration(t *testing.T) { + tests := []struct { + text string + parsed time.Duration + invalid bool + }{ + {text: "1h30.5m3s", parsed: time.Hour + 30*time.Minute + 33*time.Second}, + {text: "1h", parsed: time.Hour}, + {text: "1h2h", parsed: 3 * time.Hour}, + {text: "30m1h", parsed: time.Hour + 30*time.Minute}, + {text: "1d", parsed: 24 * time.Hour}, + {text: "0.50d", parsed: 12 * time.Hour}, + {text: ".5d", parsed: 12 * time.Hour}, + {text: "1d1h", parsed: 25 * time.Hour}, + {text: "1h1d", parsed: 25 * time.Hour}, + {text: "1h1d60m", parsed: 26 * time.Hour}, + {text: "", invalid: true}, + {text: "bla", invalid: true}, + } + + for i, tt := range tests { + var u durationValue + if err := u.Set(tt.text); err != nil { + if !tt.invalid { + t.Errorf("parsing '%s' failed unexpectedly: %v", tt.text, err) + } + continue + } + if tt.invalid { + t.Errorf("parsing '%s' should have failed", tt.text) + continue + } + if time.Duration(u) != tt.parsed { + t.Errorf(` +%d. +Input: %s +Expected: %v +Got %v`, i, tt.text, tt.parsed, u) + } + } + +} diff --git a/main.go b/main.go index 3770fa3..e7b354e 100644 --- a/main.go +++ b/main.go @@ -43,7 +43,7 @@ func main() { promServer = flag.String("url", "", "Required. URL of Prometheus server.") query = flag.String("query", "", "Required. PQL query.") queryTime = flags.UnixTime("time", time.Now(), "Required. Time for query (default is now). Format like the default format of the Unix date command.") - duration = flag.Duration("range", 0, "Required. Time to look back to. Format: 12h34m56s.") + duration = flags.Duration("range", 0, "Required. Time to look back to. Format: 5d12h34m56s") title = flag.String("title", "Prometheus metrics", "Optional. Title of graph.") // format = flag.String("format", "png", "Optional. Image format. For possible values see: https://godoc.org/github.com/gonum/plot/vg/draw#NewFormattedCanvas")