Browse Source

Merge pull request #13165 from ahmetalpbalkan/durations

Allow duration strings as --since/--until
Antonio Murdaca 10 years ago
parent
commit
f18ce101fb

+ 4 - 2
api/client/events.go

@@ -2,6 +2,7 @@ package client
 
 
 import (
 import (
 	"net/url"
 	"net/url"
+	"time"
 
 
 	"github.com/docker/docker/opts"
 	"github.com/docker/docker/opts"
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
@@ -36,11 +37,12 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
 			return err
 			return err
 		}
 		}
 	}
 	}
+	ref := time.Now()
 	if *since != "" {
 	if *since != "" {
-		v.Set("since", timeutils.GetTimestamp(*since))
+		v.Set("since", timeutils.GetTimestamp(*since, ref))
 	}
 	}
 	if *until != "" {
 	if *until != "" {
-		v.Set("until", timeutils.GetTimestamp(*until))
+		v.Set("until", timeutils.GetTimestamp(*until, ref))
 	}
 	}
 	if len(eventFilterArgs) > 0 {
 	if len(eventFilterArgs) > 0 {
 		filterJSON, err := filters.ToParam(eventFilterArgs)
 		filterJSON, err := filters.ToParam(eventFilterArgs)

+ 2 - 1
api/client/logs.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"net/url"
 	"net/url"
+	"time"
 
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
@@ -46,7 +47,7 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
 	v.Set("stderr", "1")
 	v.Set("stderr", "1")
 
 
 	if *since != "" {
 	if *since != "" {
-		v.Set("since", timeutils.GetTimestamp(*since))
+		v.Set("since", timeutils.GetTimestamp(*since, time.Now()))
 	}
 	}
 
 
 	if *times {
 	if *times {

+ 13 - 0
docs/man/docker-events.1.md

@@ -37,6 +37,10 @@ and Docker images will report:
 **--until**=""
 **--until**=""
    Stream events until this timestamp
    Stream events until this timestamp
 
 
+You can specify `--since` and `--until` parameters as an RFC 3339 date,
+a UNIX timestamp, or a Go duration string (e.g. `1m30s`, `3h`). Docker computes
+the date relative to the client machine’s time.
+
 # EXAMPLES
 # EXAMPLES
 
 
 ## Listening for Docker events
 ## Listening for Docker events
@@ -63,6 +67,15 @@ Again the output container IDs have been shortened for the purposes of this docu
     2015-01-28T20:25:45.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) die
     2015-01-28T20:25:45.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) die
     2015-01-28T20:25:46.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) stop
     2015-01-28T20:25:46.000000000-08:00 c21f6c22ba27: (from whenry/testimage:latest) stop
 
 
+The following example outputs all events that were generated in the last 3 minutes,
+relative to the current time on the client machine:
+
+    # docker events --since '3m'
+    2015-05-12T11:51:30.999999999Z07:00 4386fb97867d: (from ubuntu-1:14.04) die
+    2015-05-12T15:52:12.999999999Z07:00 4 4386fb97867d: (from ubuntu-1:14.04) stop
+    2015-05-12T15:53:45.999999999Z07:00  7805c1d35632: (from redis:2.8) die
+    2015-05-12T15:54:03.999999999Z07:00  7805c1d35632: (from redis:2.8) stop
+
 # HISTORY
 # HISTORY
 April 2014, Originally compiled by William Henry (whenry at redhat dot com)
 April 2014, Originally compiled by William Henry (whenry at redhat dot com)
 based on docker.com source material and internal work.
 based on docker.com source material and internal work.

+ 6 - 0
docs/man/docker-logs.1.md

@@ -41,6 +41,12 @@ then continue streaming new output from the container’s stdout and stderr.
 **--tail**="all"
 **--tail**="all"
    Output the specified number of lines at the end of logs (defaults to all logs)
    Output the specified number of lines at the end of logs (defaults to all logs)
 
 
+The `--since` option shows only the container logs generated after
+a given date. You can specify the date as an RFC 3339 date, a UNIX
+timestamp, or a Go duration string (e.g. `1m30s`, `3h`). Docker computes
+the date relative to the client machine’s time. You can combine
+the `--since` option with either or both of the `--follow` or `--tail` options.
+
 # HISTORY
 # HISTORY
 April 2014, Originally compiled by William Henry (whenry at redhat dot com)
 April 2014, Originally compiled by William Henry (whenry at redhat dot com)
 based on docker.com source material and internal work.
 based on docker.com source material and internal work.

+ 18 - 3
docs/sources/reference/commandline/cli.md

@@ -1123,6 +1123,10 @@ and Docker images will report:
 
 
     untag, delete
     untag, delete
 
 
+The `--since` and `--until` parameters can be Unix timestamps, RFC3339
+dates or Go duration strings (e.g. `10m`, `1h30m`) computed relative to
+client machine’s time.
+
 #### Filtering
 #### Filtering
 
 
 The filtering flag (`-f` or `--filter`) format is of "key=value". If you would
 The filtering flag (`-f` or `--filter`) format is of "key=value". If you would
@@ -1186,6 +1190,15 @@ You'll need two shells for this example.
     2014-05-10T17:42:14.999999999Z07:00 7805c1d35632: (from redis:2.8) die
     2014-05-10T17:42:14.999999999Z07:00 7805c1d35632: (from redis:2.8) die
     2014-09-03T15:49:29.999999999Z07:00 7805c1d35632: (from redis:2.8) stop
     2014-09-03T15:49:29.999999999Z07:00 7805c1d35632: (from redis:2.8) stop
 
 
+This example outputs all events that were generated in the last 3 minutes,
+relative to the current time on the client machine:
+
+    $ docker events --since '3m'
+    2015-05-12T11:51:30.999999999Z07:00 4386fb97867d: (from ubuntu-1:14.04) die
+    2015-05-12T15:52:12.999999999Z07:00 4 4386fb97867d: (from ubuntu-1:14.04) stop
+    2015-05-12T15:53:45.999999999Z07:00  7805c1d35632: (from redis:2.8) die
+    2015-05-12T15:54:03.999999999Z07:00  7805c1d35632: (from redis:2.8) stop
+
 **Filter events:**
 **Filter events:**
 
 
     $ docker events --filter 'event=stop'
     $ docker events --filter 'event=stop'
@@ -1679,9 +1692,11 @@ timestamp, for example `2014-09-16T06:17:46.000000000Z`, to each
 log entry. To ensure that the timestamps for are aligned the
 log entry. To ensure that the timestamps for are aligned the
 nano-second part of the timestamp will be padded with zero when necessary.
 nano-second part of the timestamp will be padded with zero when necessary.
 
 
-The `--since` option shows logs of a container generated only after
-the given date, specified as RFC 3339 or UNIX timestamp. The `--since` option
-can be combined with the `--follow` and `--tail` options.
+The `--since` option shows only the container logs generated after
+a given date. You can specify the date as an RFC 3339 date, a UNIX
+timestamp, or a Go duration string (e.g. `1m30s`, `3h`). Docker computes
+the date relative to the client machine’s time. You can combine
+the `--since` option with either or both of the `--follow` or `--tail` options.
 
 
 ## pause
 ## pause
 
 

+ 2 - 1
integration-cli/docker_cli_events_test.go

@@ -29,9 +29,10 @@ func (s *DockerSuite) TestEventsTimestampFormats(c *check.C) {
 	// List of available time formats to --since
 	// List of available time formats to --since
 	unixTs := func(t time.Time) string { return fmt.Sprintf("%v", t.Unix()) }
 	unixTs := func(t time.Time) string { return fmt.Sprintf("%v", t.Unix()) }
 	rfc3339 := func(t time.Time) string { return t.Format(time.RFC3339) }
 	rfc3339 := func(t time.Time) string { return t.Format(time.RFC3339) }
+	duration := func(t time.Time) string { return time.Now().Sub(t).String() }
 
 
 	// --since=$start must contain only the 'untag' event
 	// --since=$start must contain only the 'untag' event
-	for _, f := range []func(time.Time) string{unixTs, rfc3339} {
+	for _, f := range []func(time.Time) string{unixTs, rfc3339, duration} {
 		since, until := f(start), f(end)
 		since, until := f(start), f(end)
 		cmd := exec.Command(dockerBinary, "events", "--since="+since, "--until="+until)
 		cmd := exec.Command(dockerBinary, "events", "--since="+since, "--until="+until)
 		out, _, err := runCommandWithOutput(cmd)
 		out, _, err := runCommandWithOutput(cmd)

+ 11 - 4
pkg/timeutils/utils.go

@@ -6,10 +6,17 @@ import (
 	"time"
 	"time"
 )
 )
 
 
-// GetTimestamp tries to parse given string as RFC3339 time
-// or Unix timestamp (with seconds precision), if successful
-//returns a Unix timestamp as string otherwise returns value back.
-func GetTimestamp(value string) string {
+// GetTimestamp tries to parse given string as golang duration,
+// then RFC3339 time and finally as a Unix timestamp. If
+// any of these were successful, it returns a Unix timestamp
+// as string otherwise returns the given value back.
+// In case of duration input, the returned timestamp is computed
+// as the given reference time minus the amount of the duration.
+func GetTimestamp(value string, reference time.Time) string {
+	if d, err := time.ParseDuration(value); value != "0" && err == nil {
+		return strconv.FormatInt(reference.Add(-d).Unix(), 10)
+	}
+
 	var format string
 	var format string
 	if strings.Contains(value, ".") {
 	if strings.Contains(value, ".") {
 		format = time.RFC3339Nano
 		format = time.RFC3339Nano

+ 9 - 1
pkg/timeutils/utils_test.go

@@ -1,10 +1,13 @@
 package timeutils
 package timeutils
 
 
 import (
 import (
+	"fmt"
 	"testing"
 	"testing"
+	"time"
 )
 )
 
 
 func TestGetTimestamp(t *testing.T) {
 func TestGetTimestamp(t *testing.T) {
+	now := time.Now()
 	cases := []struct{ in, expected string }{
 	cases := []struct{ in, expected string }{
 		{"0", "-62167305600"}, // 0 gets parsed year 0
 		{"0", "-62167305600"}, // 0 gets parsed year 0
 
 
@@ -23,12 +26,17 @@ func TestGetTimestamp(t *testing.T) {
 		// unix timestamps returned as is
 		// unix timestamps returned as is
 		{"1136073600", "1136073600"},
 		{"1136073600", "1136073600"},
 
 
+		// Durations
+		{"1m", fmt.Sprintf("%d", now.Add(-1*time.Minute).Unix())},
+		{"1.5h", fmt.Sprintf("%d", now.Add(-90*time.Minute).Unix())},
+		{"1h30m", fmt.Sprintf("%d", now.Add(-90*time.Minute).Unix())},
+
 		// String fallback
 		// String fallback
 		{"invalid", "invalid"},
 		{"invalid", "invalid"},
 	}
 	}
 
 
 	for _, c := range cases {
 	for _, c := range cases {
-		o := GetTimestamp(c.in)
+		o := GetTimestamp(c.in, now)
 		if o != c.expected {
 		if o != c.expected {
 			t.Fatalf("wrong value for '%s'. expected:'%s' got:'%s'", c.in, c.expected, o)
 			t.Fatalf("wrong value for '%s'. expected:'%s' got:'%s'", c.in, c.expected, o)
 		}
 		}