github.com/tendermint/tmlibs@v0.9.0/autofile/autofile.go (about) 1 package autofile 2 3 import ( 4 "os" 5 "sync" 6 "time" 7 8 cmn "github.com/tendermint/tmlibs/common" 9 ) 10 11 /* AutoFile usage 12 13 // Create/Append to ./autofile_test 14 af, err := OpenAutoFile("autofile_test") 15 if err != nil { 16 panic(err) 17 } 18 19 // Stream of writes. 20 // During this time, the file may be moved e.g. by logRotate. 21 for i := 0; i < 60; i++ { 22 af.Write([]byte(Fmt("LOOP(%v)", i))) 23 time.Sleep(time.Second) 24 } 25 26 // Close the AutoFile 27 err = af.Close() 28 if err != nil { 29 panic(err) 30 } 31 */ 32 33 const autoFileOpenDuration = 1000 * time.Millisecond 34 35 // Automatically closes and re-opens file for writing. 36 // This is useful for using a log file with the logrotate tool. 37 type AutoFile struct { 38 ID string 39 Path string 40 ticker *time.Ticker 41 mtx sync.Mutex 42 file *os.File 43 } 44 45 func OpenAutoFile(path string) (af *AutoFile, err error) { 46 af = &AutoFile{ 47 ID: cmn.RandStr(12) + ":" + path, 48 Path: path, 49 ticker: time.NewTicker(autoFileOpenDuration), 50 } 51 if err = af.openFile(); err != nil { 52 return 53 } 54 go af.processTicks() 55 sighupWatchers.addAutoFile(af) 56 return 57 } 58 59 func (af *AutoFile) Close() error { 60 af.ticker.Stop() 61 err := af.closeFile() 62 sighupWatchers.removeAutoFile(af) 63 return err 64 } 65 66 func (af *AutoFile) processTicks() { 67 for { 68 _, ok := <-af.ticker.C 69 if !ok { 70 return // Done. 71 } 72 af.closeFile() 73 } 74 } 75 76 func (af *AutoFile) closeFile() (err error) { 77 af.mtx.Lock() 78 defer af.mtx.Unlock() 79 80 file := af.file 81 if file == nil { 82 return nil 83 } 84 af.file = nil 85 return file.Close() 86 } 87 88 func (af *AutoFile) Write(b []byte) (n int, err error) { 89 af.mtx.Lock() 90 defer af.mtx.Unlock() 91 92 if af.file == nil { 93 if err = af.openFile(); err != nil { 94 return 95 } 96 } 97 98 n, err = af.file.Write(b) 99 return 100 } 101 102 func (af *AutoFile) Sync() error { 103 af.mtx.Lock() 104 defer af.mtx.Unlock() 105 106 if af.file == nil { 107 if err := af.openFile(); err != nil { 108 return err 109 } 110 } 111 return af.file.Sync() 112 } 113 114 func (af *AutoFile) openFile() error { 115 file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) 116 if err != nil { 117 return err 118 } 119 af.file = file 120 return nil 121 } 122 123 func (af *AutoFile) Size() (int64, error) { 124 af.mtx.Lock() 125 defer af.mtx.Unlock() 126 127 if af.file == nil { 128 err := af.openFile() 129 if err != nil { 130 if err == os.ErrNotExist { 131 return 0, nil 132 } 133 return -1, err 134 } 135 } 136 stat, err := af.file.Stat() 137 if err != nil { 138 return -1, err 139 } 140 return stat.Size(), nil 141 142 }