github.com/hamo/docker@v1.11.1/api/client/events.go (about)

     1  package client
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"sort"
     8  	"strings"
     9  	"sync"
    10  	"time"
    11  
    12  	"golang.org/x/net/context"
    13  
    14  	"github.com/Sirupsen/logrus"
    15  	Cli "github.com/docker/docker/cli"
    16  	"github.com/docker/docker/opts"
    17  	"github.com/docker/docker/pkg/jsonlog"
    18  	flag "github.com/docker/docker/pkg/mflag"
    19  	"github.com/docker/engine-api/types"
    20  	eventtypes "github.com/docker/engine-api/types/events"
    21  	"github.com/docker/engine-api/types/filters"
    22  )
    23  
    24  // CmdEvents prints a live stream of real time events from the server.
    25  //
    26  // Usage: docker events [OPTIONS]
    27  func (cli *DockerCli) CmdEvents(args ...string) error {
    28  	cmd := Cli.Subcmd("events", nil, Cli.DockerCommands["events"].Description, true)
    29  	since := cmd.String([]string{"-since"}, "", "Show all events created since timestamp")
    30  	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
    31  	flFilter := opts.NewListOpts(nil)
    32  	cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
    33  	cmd.Require(flag.Exact, 0)
    34  
    35  	cmd.ParseFlags(args, true)
    36  
    37  	eventFilterArgs := filters.NewArgs()
    38  
    39  	// Consolidate all filter flags, and sanity check them early.
    40  	// They'll get process in the daemon/server.
    41  	for _, f := range flFilter.GetAll() {
    42  		var err error
    43  		eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs)
    44  		if err != nil {
    45  			return err
    46  		}
    47  	}
    48  
    49  	options := types.EventsOptions{
    50  		Since:   *since,
    51  		Until:   *until,
    52  		Filters: eventFilterArgs,
    53  	}
    54  
    55  	responseBody, err := cli.client.Events(context.Background(), options)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	defer responseBody.Close()
    60  
    61  	return streamEvents(responseBody, cli.out)
    62  }
    63  
    64  // streamEvents decodes prints the incoming events in the provided output.
    65  func streamEvents(input io.Reader, output io.Writer) error {
    66  	return decodeEvents(input, func(event eventtypes.Message, err error) error {
    67  		if err != nil {
    68  			return err
    69  		}
    70  		printOutput(event, output)
    71  		return nil
    72  	})
    73  }
    74  
    75  type eventProcessor func(event eventtypes.Message, err error) error
    76  
    77  func decodeEvents(input io.Reader, ep eventProcessor) error {
    78  	dec := json.NewDecoder(input)
    79  	for {
    80  		var event eventtypes.Message
    81  		err := dec.Decode(&event)
    82  		if err != nil && err == io.EOF {
    83  			break
    84  		}
    85  
    86  		if procErr := ep(event, err); procErr != nil {
    87  			return procErr
    88  		}
    89  	}
    90  	return nil
    91  }
    92  
    93  // printOutput prints all types of event information.
    94  // Each output includes the event type, actor id, name and action.
    95  // Actor attributes are printed at the end if the actor has any.
    96  func printOutput(event eventtypes.Message, output io.Writer) {
    97  	if event.TimeNano != 0 {
    98  		fmt.Fprintf(output, "%s ", time.Unix(0, event.TimeNano).Format(jsonlog.RFC3339NanoFixed))
    99  	} else if event.Time != 0 {
   100  		fmt.Fprintf(output, "%s ", time.Unix(event.Time, 0).Format(jsonlog.RFC3339NanoFixed))
   101  	}
   102  
   103  	fmt.Fprintf(output, "%s %s %s", event.Type, event.Action, event.Actor.ID)
   104  
   105  	if len(event.Actor.Attributes) > 0 {
   106  		var attrs []string
   107  		var keys []string
   108  		for k := range event.Actor.Attributes {
   109  			keys = append(keys, k)
   110  		}
   111  		sort.Strings(keys)
   112  		for _, k := range keys {
   113  			v := event.Actor.Attributes[k]
   114  			attrs = append(attrs, fmt.Sprintf("%s=%s", k, v))
   115  		}
   116  		fmt.Fprintf(output, " (%s)", strings.Join(attrs, ", "))
   117  	}
   118  	fmt.Fprint(output, "\n")
   119  }
   120  
   121  type eventHandler struct {
   122  	handlers map[string]func(eventtypes.Message)
   123  	mu       sync.Mutex
   124  }
   125  
   126  func (w *eventHandler) Handle(action string, h func(eventtypes.Message)) {
   127  	w.mu.Lock()
   128  	w.handlers[action] = h
   129  	w.mu.Unlock()
   130  }
   131  
   132  // Watch ranges over the passed in event chan and processes the events based on the
   133  // handlers created for a given action.
   134  // To stop watching, close the event chan.
   135  func (w *eventHandler) Watch(c <-chan eventtypes.Message) {
   136  	for e := range c {
   137  		w.mu.Lock()
   138  		h, exists := w.handlers[e.Action]
   139  		w.mu.Unlock()
   140  		if !exists {
   141  			continue
   142  		}
   143  		logrus.Debugf("event handler: received event: %v", e)
   144  		go h(e)
   145  	}
   146  }