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 }