gitee.com/quant1x/gox@v1.21.2/logger/logwriter.go (about) 1 package logger 2 3 import ( 4 "compress/gzip" 5 "fmt" 6 "gitee.com/quant1x/gox/api" 7 "io" 8 "os" 9 "path/filepath" 10 "strconv" 11 "time" 12 ) 13 14 const ( 15 DAY DateType = iota 16 HOUR 17 ) 18 19 type LogWriter interface { 20 Write(v []byte) 21 NeedPrefix() bool 22 } 23 24 type ConsoleWriter struct { 25 } 26 27 type RollFileWriter struct { 28 logpath string 29 name string 30 num int 31 size int64 32 currSize int64 33 currFile *os.File 34 openTime int64 35 } 36 37 type DateWriter struct { 38 logpath string 39 name string 40 dateType DateType 41 num int 42 currDate string 43 currFile *os.File 44 openTime int64 45 } 46 47 type HourWriter struct { 48 } 49 50 type DateType uint8 51 52 func reOpenFile(path string, currFile **os.File, openTime *int64) { 53 *openTime = currUnixTime 54 if *currFile != nil { 55 _ = (*currFile).Close() 56 } 57 of, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) 58 if err == nil { 59 *currFile = of 60 } else { 61 fmt.Println("open log file error", err) 62 } 63 } 64 65 func (w *ConsoleWriter) Write(v []byte) { 66 _, _ = os.Stdout.Write(v) 67 } 68 69 func (w *ConsoleWriter) NeedPrefix() bool { 70 return true 71 } 72 73 func (w *RollFileWriter) Write(v []byte) { 74 if w.currFile == nil || w.openTime+10 < currUnixTime { 75 fullPath := filepath.Join(w.logpath, w.name+".log") 76 reOpenFile(fullPath, &w.currFile, &w.openTime) 77 } 78 if w.currFile == nil { 79 return 80 } 81 n, _ := w.currFile.Write(v) 82 w.currSize += int64(n) 83 if w.currSize >= w.size { 84 w.currSize = 0 85 for i := w.num - 1; i >= 1; i-- { 86 var n1, n2 string 87 if i > 1 { 88 n1 = strconv.Itoa(i - 1) 89 } 90 n2 = strconv.Itoa(i) 91 p1 := filepath.Join(w.logpath, w.name+n1+".log") 92 p2 := filepath.Join(w.logpath, w.name+n2+".log") 93 if _, err := os.Stat(p1); !os.IsNotExist(err) { 94 _ = os.Rename(p1, p2) 95 } 96 } 97 fullPath := filepath.Join(w.logpath, w.name+".log") 98 reOpenFile(fullPath, &w.currFile, &w.openTime) 99 } 100 } 101 102 func NewRollFileWriter(logpath, name string, num, sizeMB int) *RollFileWriter { 103 w := &RollFileWriter{ 104 logpath: logpath, 105 name: name, 106 num: num, 107 size: int64(sizeMB) * 1024 * 1024, 108 } 109 fullPath := filepath.Join(logpath, name+".log") 110 st, _ := os.Stat(fullPath) 111 if st != nil { 112 w.currSize = st.Size() 113 } 114 return w 115 } 116 117 func (w *RollFileWriter) NeedPrefix() bool { 118 return true 119 } 120 121 // 压缩 使用gzip压缩成tar.gz 122 func gzipFile(source string) error { 123 dest := source + ".gz" 124 _ = os.Remove(dest) 125 newfile, err := os.Create(dest) 126 if err != nil { 127 return err 128 } 129 defer api.CloseQuietly(newfile) 130 131 file, err := os.Open(source) 132 if err != nil { 133 return err 134 } 135 136 zw := gzip.NewWriter(newfile) 137 138 filestat, err := file.Stat() 139 if err != nil { 140 return nil 141 } 142 143 zw.Name = filestat.Name() 144 zw.ModTime = filestat.ModTime() 145 _, err = io.Copy(zw, file) 146 if err != nil { 147 return nil 148 } 149 150 _ = zw.Flush() 151 if err := zw.Close(); err != nil { 152 return nil 153 } 154 return nil 155 } 156 157 func (w *DateWriter) Write(v []byte) { 158 fullPath := filepath.Join(w.logpath, w.name+".log") 159 //isNewFile := false 160 logMutex.RLock() 161 unixTime := currUnixTime 162 logMutex.RUnlock() 163 if w.currFile == nil || w.openTime+10 < unixTime { 164 reOpenFile(fullPath, &w.currFile, &w.openTime) 165 w.currDate = w.getFileDate() 166 } 167 if w.currFile == nil { 168 return 169 } 170 171 currDate := w.getCurrDate() 172 if w.currDate != currDate { 173 // 文件改名 174 sourceFile := fullPath 175 destFile := filepath.Join(w.logpath, w.name+".log."+w.currDate) 176 // 删除已有的目标文件 177 api.CloseQuietly(w.currFile) 178 w.currFile = nil 179 err := os.Remove(destFile) 180 err = os.Rename(sourceFile, destFile) 181 if err != nil { 182 // 改名失败 183 } else { 184 // 改名成功 185 } 186 w.currDate = currDate 187 188 _ = gzipFile(destFile) 189 w.cleanOldLogs() 190 reOpenFile(fullPath, &w.currFile, &w.openTime) 191 // 清理旧文件 [wangfeng on 2018/12/25 12:39] 192 _ = os.Remove(destFile) 193 } 194 _, _ = w.currFile.Write(v) 195 } 196 197 func (w *DateWriter) NeedPrefix() bool { 198 return true 199 } 200 201 func NewDateWriter(logpath, name string, dateType DateType, num int) *DateWriter { 202 w := &DateWriter{ 203 logpath: logpath, 204 name: name, 205 num: num, 206 dateType: dateType, 207 } 208 w.currDate = w.getCurrDate() 209 return w 210 } 211 212 func (w *DateWriter) getFormat() string { 213 format := timeFmtDay 214 if w.dateType == HOUR { 215 format = timeFmtHour 216 } 217 return format 218 } 219 220 func (w *DateWriter) cleanOldLogs() { 221 format := timeFmtDay 222 duration := -time.Hour * 24 223 if w.dateType == HOUR { 224 format = timeFmtHour 225 duration = -time.Hour 226 } 227 228 t := time.Now() 229 t = t.Add(duration * time.Duration(w.num)) 230 for i := 0; i < 30; i++ { 231 t = t.Add(duration) 232 k := t.Format(format) 233 fullPath := filepath.Join(w.logpath, w.name+".log."+k+".gz") 234 if _, err := os.Stat(fullPath); !os.IsNotExist(err) { 235 _ = os.Remove(fullPath) 236 } 237 } 238 return 239 } 240 241 func (w *DateWriter) getCurrDate() string { 242 logMutex.RLock() 243 defer logMutex.RUnlock() 244 if w.dateType == HOUR { 245 return currDateHour 246 } 247 return currDateDay // DAY 248 } 249 250 func (w *DateWriter) getFileDate() string { 251 fi, err := w.currFile.Stat() 252 if err == nil { 253 return fi.ModTime().Format(w.getFormat()) 254 } else { 255 return "" 256 } 257 }