github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/cmd/events.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cmd
    16  
    17  import (
    18  	"context"
    19  	"encoding/json"
    20  	"os"
    21  	"time"
    22  
    23  	"github.com/google/subcommands"
    24  	"github.com/SagerNet/gvisor/pkg/log"
    25  	"github.com/SagerNet/gvisor/runsc/config"
    26  	"github.com/SagerNet/gvisor/runsc/container"
    27  	"github.com/SagerNet/gvisor/runsc/flag"
    28  )
    29  
    30  // Events implements subcommands.Command for the "events" command.
    31  type Events struct {
    32  	// The interval between stats reporting.
    33  	intervalSec int
    34  	// If true, events will print a single group of stats and exit.
    35  	stats bool
    36  }
    37  
    38  // Name implements subcommands.Command.Name.
    39  func (*Events) Name() string {
    40  	return "events"
    41  }
    42  
    43  // Synopsis implements subcommands.Command.Synopsis.
    44  func (*Events) Synopsis() string {
    45  	return "display container events such as OOM notifications, cpu, memory, and IO usage statistics"
    46  }
    47  
    48  // Usage implements subcommands.Command.Usage.
    49  func (*Events) Usage() string {
    50  	return `<container-id>
    51  
    52  Where "<container-id>" is the name for the instance of the container.
    53  
    54  The events command displays information about the container. By default the
    55  information is displayed once every 5 seconds.
    56  
    57  OPTIONS:
    58  `
    59  }
    60  
    61  // SetFlags implements subcommands.Command.SetFlags.
    62  func (evs *Events) SetFlags(f *flag.FlagSet) {
    63  	f.IntVar(&evs.intervalSec, "interval", 5, "set the stats collection interval, in seconds")
    64  	f.BoolVar(&evs.stats, "stats", false, "display the container's stats then exit")
    65  }
    66  
    67  // Execute implements subcommands.Command.Execute.
    68  func (evs *Events) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
    69  	if f.NArg() != 1 {
    70  		f.Usage()
    71  		return subcommands.ExitUsageError
    72  	}
    73  
    74  	id := f.Arg(0)
    75  	conf := args[0].(*config.Config)
    76  
    77  	c, err := container.Load(conf.RootDir, container.FullID{ContainerID: id}, container.LoadOpts{})
    78  	if err != nil {
    79  		Fatalf("loading sandbox: %v", err)
    80  	}
    81  
    82  	// Repeatedly get stats from the container.
    83  	for {
    84  		// Get the event and print it as JSON.
    85  		ev, err := c.Event()
    86  		if err != nil {
    87  			log.Warningf("Error getting events for container: %v", err)
    88  			if evs.stats {
    89  				return subcommands.ExitFailure
    90  			}
    91  		}
    92  		log.Debugf("Events: %+v", ev)
    93  
    94  		// err must be preserved because it is used below when breaking
    95  		// out of the loop.
    96  		b, err := json.Marshal(ev.Event)
    97  		if err != nil {
    98  			log.Warningf("Error while marshalling event %v: %v", ev.Event, err)
    99  		} else {
   100  			os.Stdout.Write(b)
   101  		}
   102  
   103  		// If we're only running once, break. If we're only running
   104  		// once and there was an error, the command failed.
   105  		if evs.stats {
   106  			if err != nil {
   107  				return subcommands.ExitFailure
   108  			}
   109  			return subcommands.ExitSuccess
   110  		}
   111  
   112  		time.Sleep(time.Duration(evs.intervalSec) * time.Second)
   113  	}
   114  }