Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for less granular time formats #707

Merged
merged 2 commits into from
Apr 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 73 additions & 14 deletions cmd/observe/flows.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,55 @@ more.`,
selectorFlags := pflag.NewFlagSet("selectors", pflag.ContinueOnError)
selectorFlags.BoolVar(&selectorOpts.all, "all", false, "Get all flows stored in Hubble's buffer")
selectorFlags.Uint64Var(&selectorOpts.last, "last", 0, fmt.Sprintf("Get last N flows stored in Hubble's buffer (default %d)", defaults.FlowPrintCount))
selectorFlags.StringVar(&selectorOpts.since, "since", "", "Filter flows since a specific date (relative or RFC3339)")
selectorFlags.StringVar(&selectorOpts.until, "until", "", "Filter flows until a specific date (relative or RFC3339)")
selectorFlags.BoolVarP(&selectorOpts.follow, "follow", "f", false, "Follow flows output")
selectorFlags.StringVar(&selectorOpts.since,
"since", "",
fmt.Sprintf(`Filter flows since a specific date. The format is relative (e.g. 3s, 4m, 1h43,, ...) or one of:
StampMilli: %s
YearMonthDay: %s
YearMonthDayHour: %s
YearMonthDayHourMinute: %s
RFC3339: %s
RFC3339Milli: %s
RFC3339Micro: %s
RFC3339Nano: %s
RFC1123Z: %s
`,
time.StampMilli,
hubtime.YearMonthDay,
hubtime.YearMonthDayHour,
hubtime.YearMonthDayHourMinute,
time.RFC3339,
hubtime.RFC3339Milli,
hubtime.RFC3339Micro,
time.RFC3339Nano,
time.RFC1123Z,
),
)
selectorFlags.StringVar(&selectorOpts.until,
"until", "",
fmt.Sprintf(`Filter flows until a specific date. The format is relative (e.g. 3s, 4m, 1h43,, ...) or one of:
StampMilli: %s
YearMonthDay: %s
YearMonthDayHour: %s
YearMonthDayHourMinute: %s
RFC3339: %s
RFC3339Milli: %s
RFC3339Micro: %s
RFC3339Nano: %s
RFC1123Z: %s
`,
time.StampMilli,
hubtime.YearMonthDay,
hubtime.YearMonthDayHour,
hubtime.YearMonthDayHourMinute,
time.RFC3339,
hubtime.RFC3339Milli,
hubtime.RFC3339Micro,
time.RFC3339Nano,
time.RFC1123Z,
),
)
observeCmd.PersistentFlags().AddFlagSet(selectorFlags)

// filter flags
Expand Down Expand Up @@ -349,23 +395,36 @@ more.`,
formattingFlags.StringVarP(
&formattingOpts.output, "output", "o", "compact",
`Specify the output format, one of:
compact: Compact output
dict: Each flow is shown as KEY:VALUE pair
json: JSON encoding
jsonpb: Output each GetFlowResponse according to proto3's JSON mapping
table: Tab-aligned columns
compact: Compact output
dict: Each flow is shown as KEY:VALUE pair
json: JSON encoding
jsonpb: Output each GetFlowResponse according to proto3's JSON mapping
table: Tab-aligned columns
`)
formattingFlags.BoolVarP(&formattingOpts.nodeName, "print-node-name", "", false, "Print node name in output")
formattingFlags.StringVar(
&formattingOpts.timeFormat, "time-format", "StampMilli",
fmt.Sprintf(`Specify the time format for printing. This option does not apply to the json and jsonpb output type. One of:
kaworu marked this conversation as resolved.
Show resolved Hide resolved
StampMilli: %s
RFC3339: %s
RFC3339Milli: %s
RFC3339Micro: %s
RFC3339Nano: %s
RFC1123Z: %s
`, time.StampMilli, time.RFC3339, hubtime.RFC3339Milli, hubtime.RFC3339Micro, time.RFC3339Nano, time.RFC1123Z),
StampMilli: %s
YearMonthDay: %s
YearMonthDayHour: %s
YearMonthDayHourMinute: %s
RFC3339: %s
RFC3339Milli: %s
RFC3339Micro: %s
RFC3339Nano: %s
RFC1123Z: %s
`,
time.StampMilli,
hubtime.YearMonthDay,
hubtime.YearMonthDayHour,
hubtime.YearMonthDayHourMinute,
time.RFC3339,
hubtime.RFC3339Milli,
hubtime.RFC3339Micro,
time.RFC3339Nano,
time.RFC1123Z,
),
)
observeCmd.PersistentFlags().AddFlagSet(formattingFlags)

Expand Down
21 changes: 21 additions & 0 deletions pkg/time/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ import (
)

const (
// YearMonthDay is a time format similar to RFC3339 with day granularity
// instead of second.
YearMonthDay = "2006-01-02"
// YearMonthDayHour is a time format similar to RFC3339 with hour
// granularity instead of second.
YearMonthDayHour = "2006-01-02T15Z07:00"
// YearMonthDayHourMinute is a time format similar to RFC3339 with minute
// granularity instead of second.
YearMonthDayHourMinute = "2006-01-02T15:04Z07:00"
// RFC3339Milli is a time format layout for use in time.Format and
// time.Parse. It follows the RFC3339 format with millisecond precision.
RFC3339Milli = "2006-01-02T15:04:05.999Z07:00"
Expand All @@ -38,6 +47,9 @@ var (
// layouts is a set of supported time format layouts. Format that only apply to
// local times should not be added to this list.
var layouts = []string{
YearMonthDay,
YearMonthDayHour,
YearMonthDayHourMinute,
time.RFC3339,
time.RFC3339Nano,
RFC3339Milli,
Expand Down Expand Up @@ -68,6 +80,9 @@ func FromString(input string) (time.Time, error) {

// FormatNames are the valid time format names accepted by this package.
var FormatNames = []string{
"YearMonthDay",
"YearMonthDayHour",
"YearMonthDayHourMinute",
"StampMilli",
"RFC3339",
"RFC3339Milli",
Expand All @@ -79,6 +94,12 @@ var FormatNames = []string{
// FormatNameToLayout returns the time format layout for the time format name.
func FormatNameToLayout(name string) string {
switch strings.ToLower(name) {
case "yearmonthday":
return YearMonthDay
case "yearmonthdayhour":
return YearMonthDayHour
case "yearmonthdayhourminute":
return YearMonthDayHourMinute
case "rfc3339":
return time.RFC3339
case "rfc3339milli":
Expand Down
44 changes: 33 additions & 11 deletions pkg/time/time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,44 @@ func TestFromString(t *testing.T) {
input: "2019-06-30T18:00:00Z",
expected: "2019-06-30T18:00:00Z",
},
{
input: "2019-06-30",
expected: "2019-06-30T00:00:00Z",
},
{
input: "2019-06-30T18Z",
expected: "2019-06-30T18:00:00Z",
},
rolinh marked this conversation as resolved.
Show resolved Hide resolved
{
input: "2019-06-30T18:45Z",
expected: "2019-06-30T18:45:00Z",
},
rolinh marked this conversation as resolved.
Show resolved Hide resolved
{
input: "2019-06-30T18+02:00",
expected: "2019-06-30T16:00:00Z",
},
{
input: "2019-06-30T18:45+02:00",
expected: "2019-06-30T16:45:00Z",
},
}

for _, tt := range tests {
got, err := FromString(tt.input)
if err != nil {
t.Errorf("failed to parse %s", tt.input)
}
t.Run(tt.input, func(t *testing.T) {
got, err := FromString(tt.input)
if err != nil {
t.Errorf("failed to parse %s", tt.input)
}

expected, err := FromString(tt.expected)
if err != nil {
t.Errorf("failed to parse %s", tt.expected)
}
expected, err := FromString(tt.expected)
if err != nil {
t.Errorf("failed to parse %s", tt.expected)
}

if !got.Equal(expected) {
t.Errorf("%s should equal %s", got, expected)
}
if !got.Equal(expected) {
t.Errorf("%s should equal %s", got, expected)
}
})
}
}

Expand Down