package system import ( "fmt" "io" "sort" "strings" "time" "golang.org/x/net/context" "github.com/docker/docker/api/client" "github.com/docker/docker/cli" "github.com/docker/docker/pkg/jsonlog" "github.com/docker/engine-api/types" eventtypes "github.com/docker/engine-api/types/events" "github.com/docker/engine-api/types/filters" "github.com/spf13/cobra" ) type eventsOptions struct { since string until string filter []string } // NewEventsCommand creats a new cobra.Command for `docker events` func NewEventsCommand(dockerCli *client.DockerCli) *cobra.Command { var opts eventsOptions cmd := &cobra.Command{ Use: "events [OPTIONS]", Short: "Get real time events from the server", Args: cli.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { return runEvents(dockerCli, &opts) }, } flags := cmd.Flags() flags.StringVar(&opts.since, "since", "", "Show all events created since timestamp") flags.StringVar(&opts.until, "until", "", "Stream events until this timestamp") flags.StringSliceVarP(&opts.filter, "filter", "f", []string{}, "Filter output based on conditions provided") return cmd } func runEvents(dockerCli *client.DockerCli, opts *eventsOptions) error { eventFilterArgs := filters.NewArgs() // Consolidate all filter flags, and sanity check them early. // They'll get process in the daemon/server. for _, f := range opts.filter { var err error eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs) if err != nil { return err } } options := types.EventsOptions{ Since: opts.since, Until: opts.until, Filters: eventFilterArgs, } responseBody, err := dockerCli.Client().Events(context.Background(), options) if err != nil { return err } defer responseBody.Close() return streamEvents(responseBody, dockerCli.Out()) } // streamEvents decodes prints the incoming events in the provided output. func streamEvents(input io.Reader, output io.Writer) error { return DecodeEvents(input, func(event eventtypes.Message, err error) error { if err != nil { return err } printOutput(event, output) return nil }) } type eventProcessor func(event eventtypes.Message, err error) error // printOutput prints all types of event information. // Each output includes the event type, actor id, name and action. // Actor attributes are printed at the end if the actor has any. func printOutput(event eventtypes.Message, output io.Writer) { if event.TimeNano != 0 { fmt.Fprintf(output, "%s ", time.Unix(0, event.TimeNano).Format(jsonlog.RFC3339NanoFixed)) } else if event.Time != 0 { fmt.Fprintf(output, "%s ", time.Unix(event.Time, 0).Format(jsonlog.RFC3339NanoFixed)) } fmt.Fprintf(output, "%s %s %s", event.Type, event.Action, event.Actor.ID) if len(event.Actor.Attributes) > 0 { var attrs []string var keys []string for k := range event.Actor.Attributes { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { v := event.Actor.Attributes[k] attrs = append(attrs, fmt.Sprintf("%s=%s", k, v)) } fmt.Fprintf(output, " (%s)", strings.Join(attrs, ", ")) } fmt.Fprint(output, "\n") }