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