gitee.com/quant1x/gox@v1.7.6/logger/logwriter.go (about)

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