diff --git a/daemon/events/events.go b/daemon/events/events.go index 6687e2f155..0334dece47 100644 --- a/daemon/events/events.go +++ b/daemon/events/events.go @@ -45,7 +45,8 @@ func (e *Events) Evict(l chan interface{}) { // Log broadcasts event to listeners. Each listener has 100 millisecond for // receiving event or it will be skipped. func (e *Events) Log(action, id, from string) { - jm := &jsonmessage.JSONMessage{Status: action, ID: id, From: from, Time: time.Now().UTC().Unix()} + now := time.Now().UTC() + jm := &jsonmessage.JSONMessage{Status: action, ID: id, From: from, Time: now.Unix(), TimeNano: now.UnixNano()} e.mu.Lock() if len(e.events) == cap(e.events) { // discard oldest event diff --git a/docs/reference/api/docker_remote_api.md b/docs/reference/api/docker_remote_api.md index 2b6b4c9503..8cf91ee145 100644 --- a/docs/reference/api/docker_remote_api.md +++ b/docs/reference/api/docker_remote_api.md @@ -87,6 +87,7 @@ This section lists each version from latest to oldest. Each listing includes a * The `hostConfig` option now accepts the field `DnsOptions`, which specifies a list of DNS options to be used in the container. * `POST /build` now optionally takes a serialized map of build-time variables. +* `GET /events` now includes a `timenano` field, in addition to the existing `time` field. ### v1.20 API changes diff --git a/docs/reference/api/docker_remote_api_v1.21.md b/docs/reference/api/docker_remote_api_v1.21.md index 0ac6040555..a5a3f220ce 100644 --- a/docs/reference/api/docker_remote_api_v1.21.md +++ b/docs/reference/api/docker_remote_api_v1.21.md @@ -2014,10 +2014,10 @@ and Docker images report: HTTP/1.1 200 OK Content-Type: application/json - {"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} - {"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924} - {"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966} - {"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970} + {"status":"pull","id":"busybox:latest","time":1442421700,"timeNano":1442421700598988358} + {"status":"create","id":"5745704abe9caa5","from":"busybox","time":1442421716,"timeNano":1442421716853979870} + {"status":"attach","id":"5745704abe9caa5","from":"busybox","time":1442421716,"timeNano":1442421716894759198} + {"status":"start","id":"5745704abe9caa5","from":"busybox","time":1442421716,"timeNano":1442421716983607193} Query Parameters: diff --git a/pkg/jsonmessage/jsonmessage.go b/pkg/jsonmessage/jsonmessage.go index f12547c664..451c6a9fd2 100644 --- a/pkg/jsonmessage/jsonmessage.go +++ b/pkg/jsonmessage/jsonmessage.go @@ -99,6 +99,7 @@ type JSONMessage struct { ID string `json:"id,omitempty"` From string `json:"from,omitempty"` Time int64 `json:"time,omitempty"` + TimeNano int64 `json:"timeNano,omitempty"` Error *JSONError `json:"errorDetail,omitempty"` ErrorMessage string `json:"error,omitempty"` //deprecated } @@ -121,7 +122,9 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error { } else if jm.Progress != nil && jm.Progress.String() != "" { //disable progressbar in non-terminal return nil } - if jm.Time != 0 { + if jm.TimeNano != 0 { + fmt.Fprintf(out, "%s ", time.Unix(0, jm.TimeNano).Format(timeutils.RFC3339NanoFixed)) + } else if jm.Time != 0 { fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(timeutils.RFC3339NanoFixed)) } if jm.ID != "" { diff --git a/pkg/jsonmessage/jsonmessage_test.go b/pkg/jsonmessage/jsonmessage_test.go index 889b0ba5e2..7f46a8f63e 100644 --- a/pkg/jsonmessage/jsonmessage_test.go +++ b/pkg/jsonmessage/jsonmessage_test.go @@ -53,7 +53,7 @@ func TestProgress(t *testing.T) { } func TestJSONMessageDisplay(t *testing.T) { - now := time.Now().Unix() + now := time.Now() messages := map[JSONMessage][]string{ // Empty JSONMessage{}: {"\n", "\n"}, @@ -66,13 +66,34 @@ func TestJSONMessageDisplay(t *testing.T) { }, // General JSONMessage{ - Time: now, + Time: now.Unix(), ID: "ID", From: "From", Status: "status", }: { - fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now, 0).Format(timeutils.RFC3339NanoFixed)), - fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now, 0).Format(timeutils.RFC3339NanoFixed)), + fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(timeutils.RFC3339NanoFixed)), + fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(timeutils.RFC3339NanoFixed)), + }, + // General, with nano precision time + JSONMessage{ + TimeNano: now.UnixNano(), + ID: "ID", + From: "From", + Status: "status", + }: { + fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(timeutils.RFC3339NanoFixed)), + fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(timeutils.RFC3339NanoFixed)), + }, + // General, with both times Nano is preferred + JSONMessage{ + Time: now.Unix(), + TimeNano: now.UnixNano(), + ID: "ID", + From: "From", + Status: "status", + }: { + fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(timeutils.RFC3339NanoFixed)), + fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(timeutils.RFC3339NanoFixed)), }, // Stream over status JSONMessage{