github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/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/MerlinKodo/gvisor/pkg/log" 24 "github.com/MerlinKodo/gvisor/runsc/cmd/util" 25 "github.com/MerlinKodo/gvisor/runsc/config" 26 "github.com/MerlinKodo/gvisor/runsc/container" 27 "github.com/MerlinKodo/gvisor/runsc/flag" 28 "github.com/google/subcommands" 29 ) 30 31 // Events implements subcommands.Command for the "events" command. 32 type Events struct { 33 // The interval between stats reporting. 34 intervalSec int 35 // If true, events will print a single group of stats and exit. 36 stats bool 37 } 38 39 // Name implements subcommands.Command.Name. 40 func (*Events) Name() string { 41 return "events" 42 } 43 44 // Synopsis implements subcommands.Command.Synopsis. 45 func (*Events) Synopsis() string { 46 return "display container events such as OOM notifications, cpu, memory, and IO usage statistics" 47 } 48 49 // Usage implements subcommands.Command.Usage. 50 func (*Events) Usage() string { 51 return `<container-id> 52 53 Where "<container-id>" is the name for the instance of the container. 54 55 The events command displays information about the container. By default the 56 information is displayed once every 5 seconds. 57 58 OPTIONS: 59 ` 60 } 61 62 // SetFlags implements subcommands.Command.SetFlags. 63 func (evs *Events) SetFlags(f *flag.FlagSet) { 64 f.IntVar(&evs.intervalSec, "interval", 5, "set the stats collection interval, in seconds") 65 f.BoolVar(&evs.stats, "stats", false, "display the container's stats then exit") 66 } 67 68 // Execute implements subcommands.Command.Execute. 69 func (evs *Events) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus { 70 if f.NArg() != 1 { 71 f.Usage() 72 return subcommands.ExitUsageError 73 } 74 75 id := f.Arg(0) 76 conf := args[0].(*config.Config) 77 78 c, err := container.Load(conf.RootDir, container.FullID{ContainerID: id}, container.LoadOpts{}) 79 if err != nil { 80 util.Fatalf("loading sandbox: %v", err) 81 } 82 83 // Repeatedly get stats from the container. Sleep a bit after every loop 84 // except the first one. 85 for dur := time.Duration(evs.intervalSec) * time.Second; true; time.Sleep(dur) { 86 // Get the event and print it as JSON. 87 ev, err := c.Event() 88 if err != nil { 89 log.Warningf("Error getting events for container: %v", err) 90 if evs.stats { 91 return subcommands.ExitFailure 92 } 93 continue 94 } 95 log.Debugf("Events: %+v", ev) 96 97 if err := json.NewEncoder(os.Stdout).Encode(ev.Event); err != nil { 98 log.Warningf("Error encoding event %+v: %v", ev.Event, err) 99 if evs.stats { 100 return subcommands.ExitFailure 101 } 102 continue 103 } 104 105 // Break if we're only running once. If we got this far it was a success. 106 if evs.stats { 107 return subcommands.ExitSuccess 108 } 109 } 110 panic("should never get here") 111 }