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  }