events.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package client
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "sort"
  7. "strings"
  8. "time"
  9. Cli "github.com/docker/docker/cli"
  10. "github.com/docker/docker/opts"
  11. "github.com/docker/docker/pkg/jsonlog"
  12. flag "github.com/docker/docker/pkg/mflag"
  13. "github.com/docker/engine-api/types"
  14. eventtypes "github.com/docker/engine-api/types/events"
  15. "github.com/docker/engine-api/types/filters"
  16. )
  17. // CmdEvents prints a live stream of real time events from the server.
  18. //
  19. // Usage: docker events [OPTIONS]
  20. func (cli *DockerCli) CmdEvents(args ...string) error {
  21. cmd := Cli.Subcmd("events", nil, Cli.DockerCommands["events"].Description, true)
  22. since := cmd.String([]string{"-since"}, "", "Show all events created since timestamp")
  23. until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
  24. flFilter := opts.NewListOpts(nil)
  25. cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
  26. cmd.Require(flag.Exact, 0)
  27. cmd.ParseFlags(args, true)
  28. eventFilterArgs := filters.NewArgs()
  29. // Consolidate all filter flags, and sanity check them early.
  30. // They'll get process in the daemon/server.
  31. for _, f := range flFilter.GetAll() {
  32. var err error
  33. eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs)
  34. if err != nil {
  35. return err
  36. }
  37. }
  38. options := types.EventsOptions{
  39. Since: *since,
  40. Until: *until,
  41. Filters: eventFilterArgs,
  42. }
  43. responseBody, err := cli.client.Events(options)
  44. if err != nil {
  45. return err
  46. }
  47. defer responseBody.Close()
  48. return streamEvents(responseBody, cli.out)
  49. }
  50. // streamEvents decodes prints the incoming events in the provided output.
  51. func streamEvents(input io.Reader, output io.Writer) error {
  52. return decodeEvents(input, func(event eventtypes.Message, err error) error {
  53. if err != nil {
  54. return err
  55. }
  56. printOutput(event, output)
  57. return nil
  58. })
  59. }
  60. type eventProcessor func(event eventtypes.Message, err error) error
  61. func decodeEvents(input io.Reader, ep eventProcessor) error {
  62. dec := json.NewDecoder(input)
  63. for {
  64. var event eventtypes.Message
  65. err := dec.Decode(&event)
  66. if err != nil && err == io.EOF {
  67. break
  68. }
  69. if procErr := ep(event, err); procErr != nil {
  70. return procErr
  71. }
  72. }
  73. return nil
  74. }
  75. // printOutput prints all types of event information.
  76. // Each output includes the event type, actor id, name and action.
  77. // Actor attributes are printed at the end if the actor has any.
  78. func printOutput(event eventtypes.Message, output io.Writer) {
  79. if event.TimeNano != 0 {
  80. fmt.Fprintf(output, "%s ", time.Unix(0, event.TimeNano).Format(jsonlog.RFC3339NanoFixed))
  81. } else if event.Time != 0 {
  82. fmt.Fprintf(output, "%s ", time.Unix(event.Time, 0).Format(jsonlog.RFC3339NanoFixed))
  83. }
  84. fmt.Fprintf(output, "%s %s %s", event.Type, event.Action, event.Actor.ID)
  85. if len(event.Actor.Attributes) > 0 {
  86. var attrs []string
  87. var keys []string
  88. for k := range event.Actor.Attributes {
  89. keys = append(keys, k)
  90. }
  91. sort.Strings(keys)
  92. for _, k := range keys {
  93. v := event.Actor.Attributes[k]
  94. attrs = append(attrs, fmt.Sprintf("%s=%s", k, v))
  95. }
  96. fmt.Fprintf(output, " (%s)", strings.Join(attrs, ", "))
  97. }
  98. fmt.Fprint(output, "\n")
  99. }