events.go 3.1 KB

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