123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- package system
- import (
- "fmt"
- "io"
- "io/ioutil"
- "sort"
- "strings"
- "text/template"
- "time"
- "golang.org/x/net/context"
- "github.com/docker/docker/api/types"
- eventtypes "github.com/docker/docker/api/types/events"
- "github.com/docker/docker/cli"
- "github.com/docker/docker/cli/command"
- "github.com/docker/docker/opts"
- "github.com/docker/docker/pkg/jsonlog"
- "github.com/docker/docker/utils/templates"
- "github.com/spf13/cobra"
- )
- type eventsOptions struct {
- since string
- until string
- filter opts.FilterOpt
- format string
- }
- // NewEventsCommand creates a new cobra.Command for `docker events`
- func NewEventsCommand(dockerCli *command.DockerCli) *cobra.Command {
- opts := eventsOptions{filter: opts.NewFilterOpt()}
- 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.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
- flags.StringVar(&opts.format, "format", "", "Format the output using the given Go template")
- return cmd
- }
- func runEvents(dockerCli *command.DockerCli, opts *eventsOptions) error {
- tmpl, err := makeTemplate(opts.format)
- if err != nil {
- return cli.StatusError{
- StatusCode: 64,
- Status: "Error parsing format: " + err.Error()}
- }
- options := types.EventsOptions{
- Since: opts.since,
- Until: opts.until,
- Filters: opts.filter.Value(),
- }
- ctx, cancel := context.WithCancel(context.Background())
- events, errs := dockerCli.Client().Events(ctx, options)
- defer cancel()
- out := dockerCli.Out()
- for {
- select {
- case event := <-events:
- if err := handleEvent(out, event, tmpl); err != nil {
- return err
- }
- case err := <-errs:
- if err == io.EOF {
- return nil
- }
- return err
- }
- }
- }
- func handleEvent(out io.Writer, event eventtypes.Message, tmpl *template.Template) error {
- if tmpl == nil {
- return prettyPrintEvent(out, event)
- }
- return formatEvent(out, event, tmpl)
- }
- func makeTemplate(format string) (*template.Template, error) {
- if format == "" {
- return nil, nil
- }
- tmpl, err := templates.Parse(format)
- if err != nil {
- return tmpl, err
- }
- // we execute the template for an empty message, so as to validate
- // a bad template like "{{.badFieldString}}"
- return tmpl, tmpl.Execute(ioutil.Discard, &eventtypes.Message{})
- }
- // prettyPrintEvent 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 prettyPrintEvent(out io.Writer, event eventtypes.Message) error {
- if event.TimeNano != 0 {
- fmt.Fprintf(out, "%s ", time.Unix(0, event.TimeNano).Format(jsonlog.RFC3339NanoFixed))
- } else if event.Time != 0 {
- fmt.Fprintf(out, "%s ", time.Unix(event.Time, 0).Format(jsonlog.RFC3339NanoFixed))
- }
- fmt.Fprintf(out, "%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(out, " (%s)", strings.Join(attrs, ", "))
- }
- fmt.Fprint(out, "\n")
- return nil
- }
- func formatEvent(out io.Writer, event eventtypes.Message, tmpl *template.Template) error {
- defer out.Write([]byte{'\n'})
- return tmpl.Execute(out, event)
- }
|