github.com/vmware/govmomi@v0.51.0/cli/datastore/tail.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package datastore 6 7 import ( 8 "context" 9 "flag" 10 "io" 11 "os" 12 "time" 13 14 "github.com/vmware/govmomi/cli" 15 "github.com/vmware/govmomi/cli/flags" 16 ) 17 18 type tail struct { 19 *flags.DatastoreFlag 20 *flags.HostSystemFlag 21 22 count int64 23 lines int 24 follow bool 25 } 26 27 func init() { 28 cli.Register("datastore.tail", &tail{}) 29 } 30 31 func (cmd *tail) Register(ctx context.Context, f *flag.FlagSet) { 32 cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx) 33 cmd.DatastoreFlag.Register(ctx, f) 34 35 cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx) 36 cmd.HostSystemFlag.Register(ctx, f) 37 38 f.Int64Var(&cmd.count, "c", -1, "Output the last NUM bytes") 39 f.IntVar(&cmd.lines, "n", 10, "Output the last NUM lines") 40 f.BoolVar(&cmd.follow, "f", false, "Output appended data as the file grows") 41 } 42 43 func (cmd *tail) Description() string { 44 return `Output the last part of datastore files. 45 46 Examples: 47 govc datastore.tail -n 100 vm-name/vmware.log 48 govc datastore.tail -n 0 -f vm-name/vmware.log` 49 } 50 51 func (cmd *tail) Process(ctx context.Context) error { 52 if err := cmd.DatastoreFlag.Process(ctx); err != nil { 53 return err 54 } 55 if err := cmd.HostSystemFlag.Process(ctx); err != nil { 56 return err 57 } 58 return nil 59 } 60 61 func (cmd *tail) Usage() string { 62 return "PATH" 63 } 64 65 func (cmd *tail) Run(ctx context.Context, f *flag.FlagSet) error { 66 if f.NArg() != 1 { 67 return flag.ErrHelp 68 } 69 70 p := cmd.Args(f.Args())[0] 71 72 ds, err := cmd.Datastore() 73 if err != nil { 74 return err 75 } 76 77 h, err := cmd.HostSystemIfSpecified() 78 if err != nil { 79 return err 80 } 81 82 if h != nil { 83 ctx = ds.HostContext(ctx, h) 84 } 85 86 file, err := ds.Open(ctx, p.Path) 87 if err != nil { 88 return err 89 } 90 91 var reader io.ReadCloser = file 92 93 var offset int64 94 95 if cmd.count >= 0 { 96 info, serr := file.Stat() 97 if serr != nil { 98 return serr 99 } 100 101 if info.Size() > cmd.count { 102 offset = info.Size() - cmd.count 103 104 _, err = file.Seek(offset, io.SeekStart) 105 if err != nil { 106 return err 107 } 108 } 109 } else if cmd.lines >= 0 { 110 err = file.Tail(cmd.lines) 111 if err != nil { 112 return err 113 } 114 } 115 116 if cmd.follow { 117 reader = file.Follow(time.Second) 118 } 119 120 _, err = io.Copy(os.Stdout, reader) 121 122 _ = reader.Close() 123 124 return err 125 }