events.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package system
  2. import (
  3. "fmt"
  4. "io"
  5. "io/ioutil"
  6. "sort"
  7. "strings"
  8. "text/template"
  9. "time"
  10. "golang.org/x/net/context"
  11. "github.com/docker/docker/api/types"
  12. eventtypes "github.com/docker/docker/api/types/events"
  13. "github.com/docker/docker/cli"
  14. "github.com/docker/docker/cli/command"
  15. "github.com/docker/docker/opts"
  16. "github.com/docker/docker/pkg/jsonlog"
  17. "github.com/docker/docker/utils/templates"
  18. "github.com/spf13/cobra"
  19. )
  20. type eventsOptions struct {
  21. since string
  22. until string
  23. filter opts.FilterOpt
  24. format string
  25. }
  26. // NewEventsCommand creates a new cobra.Command for `docker events`
  27. func NewEventsCommand(dockerCli *command.DockerCli) *cobra.Command {
  28. opts := eventsOptions{filter: opts.NewFilterOpt()}
  29. cmd := &cobra.Command{
  30. Use: "events [OPTIONS]",
  31. Short: "Get real time events from the server",
  32. Args: cli.NoArgs,
  33. RunE: func(cmd *cobra.Command, args []string) error {
  34. return runEvents(dockerCli, &opts)
  35. },
  36. }
  37. flags := cmd.Flags()
  38. flags.StringVar(&opts.since, "since", "", "Show all events created since timestamp")
  39. flags.StringVar(&opts.until, "until", "", "Stream events until this timestamp")
  40. flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
  41. flags.StringVar(&opts.format, "format", "", "Format the output using the given Go template")
  42. return cmd
  43. }
  44. func runEvents(dockerCli *command.DockerCli, opts *eventsOptions) error {
  45. tmpl, err := makeTemplate(opts.format)
  46. if err != nil {
  47. return cli.StatusError{
  48. StatusCode: 64,
  49. Status: "Error parsing format: " + err.Error()}
  50. }
  51. options := types.EventsOptions{
  52. Since: opts.since,
  53. Until: opts.until,
  54. Filters: opts.filter.Value(),
  55. }
  56. ctx, cancel := context.WithCancel(context.Background())
  57. events, errs := dockerCli.Client().Events(ctx, options)
  58. defer cancel()
  59. out := dockerCli.Out()
  60. for {
  61. select {
  62. case event := <-events:
  63. if err := handleEvent(out, event, tmpl); err != nil {
  64. return err
  65. }
  66. case err := <-errs:
  67. if err == io.EOF {
  68. return nil
  69. }
  70. return err
  71. }
  72. }
  73. }
  74. func handleEvent(out io.Writer, event eventtypes.Message, tmpl *template.Template) error {
  75. if tmpl == nil {
  76. return prettyPrintEvent(out, event)
  77. }
  78. return formatEvent(out, event, tmpl)
  79. }
  80. func makeTemplate(format string) (*template.Template, error) {
  81. if format == "" {
  82. return nil, nil
  83. }
  84. tmpl, err := templates.Parse(format)
  85. if err != nil {
  86. return tmpl, err
  87. }
  88. // we execute the template for an empty message, so as to validate
  89. // a bad template like "{{.badFieldString}}"
  90. return tmpl, tmpl.Execute(ioutil.Discard, &eventtypes.Message{})
  91. }
  92. // prettyPrintEvent prints all types of event information.
  93. // Each output includes the event type, actor id, name and action.
  94. // Actor attributes are printed at the end if the actor has any.
  95. func prettyPrintEvent(out io.Writer, event eventtypes.Message) error {
  96. if event.TimeNano != 0 {
  97. fmt.Fprintf(out, "%s ", time.Unix(0, event.TimeNano).Format(jsonlog.RFC3339NanoFixed))
  98. } else if event.Time != 0 {
  99. fmt.Fprintf(out, "%s ", time.Unix(event.Time, 0).Format(jsonlog.RFC3339NanoFixed))
  100. }
  101. fmt.Fprintf(out, "%s %s %s", event.Type, event.Action, event.Actor.ID)
  102. if len(event.Actor.Attributes) > 0 {
  103. var attrs []string
  104. var keys []string
  105. for k := range event.Actor.Attributes {
  106. keys = append(keys, k)
  107. }
  108. sort.Strings(keys)
  109. for _, k := range keys {
  110. v := event.Actor.Attributes[k]
  111. attrs = append(attrs, fmt.Sprintf("%s=%s", k, v))
  112. }
  113. fmt.Fprintf(out, " (%s)", strings.Join(attrs, ", "))
  114. }
  115. fmt.Fprint(out, "\n")
  116. return nil
  117. }
  118. func formatEvent(out io.Writer, event eventtypes.Message, tmpl *template.Template) error {
  119. defer out.Write([]byte{'\n'})
  120. return tmpl.Execute(out, event)
  121. }