github.com/JohanShen/go-utils@v1.1.4-0.20201117124024-901319a2b2a0/logger/time_writer.go (about)

     1  package logger
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/JohanShen/go-utils/utils"
     6  	"os"
     7  	"path/filepath"
     8  	"sync"
     9  	"time"
    10  )
    11  
    12  type TimeWriter struct {
    13  	dir, fileName string
    14  	lastMakeTime  time.Time
    15  	fileMode      os.FileMode
    16  	CurrentPath   string
    17  	PathTemplate  string
    18  	files         map[string]*fileObject
    19  	locker        *sync.Mutex
    20  }
    21  
    22  type fileObject struct {
    23  	file       *os.File
    24  	writeLen   int
    25  	createTime time.Time
    26  }
    27  
    28  func NewTimeWriter(logTemplate string) (obj *TimeWriter) {
    29  	obj = &TimeWriter{
    30  		PathTemplate: logTemplate,
    31  		locker:       &sync.Mutex{},
    32  		fileMode:     0666,
    33  		files:        make(map[string]*fileObject),
    34  	}
    35  	return obj
    36  }
    37  
    38  // 创建新的文件对象
    39  func (l *TimeWriter) makeNewFile(logPath string) (file *os.File, err error) {
    40  	//now := time.Now()
    41  	//logPath := utils.XTime(now).Format(l.PathTemplate)
    42  	l.dir, l.fileName = filepath.Split(logPath)
    43  	if ok, _ := utils.IsDirExists(l.dir); !ok {
    44  		if err := os.MkdirAll(l.dir, l.fileMode); err != nil {
    45  			return nil, err
    46  		}
    47  	}
    48  
    49  	file, err = os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, l.fileMode)
    50  	return file, err
    51  }
    52  
    53  func (l *TimeWriter) Write(p []byte) (n int, err error) {
    54  	l.locker.Lock()
    55  	defer l.locker.Unlock()
    56  
    57  	now := time.Now()
    58  	logPath := utils.XTime(now).Format(l.PathTemplate)
    59  
    60  	var file *fileObject
    61  	ok := false
    62  	for {
    63  		if file, ok = l.files[logPath]; ok {
    64  			break
    65  		}
    66  		if obj, err := l.makeNewFile(logPath); err == nil {
    67  			l.files[logPath] = &fileObject{file: obj, createTime: now}
    68  			l.CurrentPath = logPath
    69  			l.lastMakeTime = now
    70  		} else {
    71  			fmt.Printf("write fail, msg(%s)\n", err)
    72  			return 0, err
    73  		}
    74  		go l.closeFile()
    75  	}
    76  
    77  	n, err = file.file.Write(p)
    78  	file.writeLen += n
    79  	return n, err
    80  }
    81  
    82  func (l *TimeWriter) closeFile() {
    83  
    84  	if len(l.files) > 1 {
    85  		now := time.Now()
    86  		closeFiles := make([]string, 0, len(l.files))
    87  		// 需要将之前的文件句柄关闭
    88  		for key, item := range l.files {
    89  			// 将非当前文件,且超过15分钟的文件句柄关闭
    90  			if key == l.CurrentPath || item.createTime.Sub(now) > time.Minute*-15 {
    91  				continue
    92  			}
    93  			closeFiles = append(closeFiles, key)
    94  			if err := item.file.Sync(); err != nil {
    95  				//有问题但是不处理
    96  				println("写入文件时 closeFile() ", err)
    97  			}
    98  			if err := item.file.Close(); err != nil {
    99  				//有问题但是不处理
   100  				println("关闭文件时 closeFile() ", err)
   101  			}
   102  		}
   103  		if len(closeFiles) > 0 {
   104  			l.locker.Lock()
   105  			for _, v := range closeFiles {
   106  				delete(l.files, v)
   107  			}
   108  			l.locker.Unlock()
   109  		}
   110  	}
   111  }
   112  
   113  func (l *TimeWriter) Close() error {
   114  	l.locker.Lock()
   115  	defer l.locker.Unlock()
   116  
   117  	for _, item := range l.files {
   118  		if err := item.file.Sync(); err != nil {
   119  			//有问题但是不处理
   120  			println("写入文件时 Close() ", err)
   121  		}
   122  		if err := item.file.Close(); err != nil {
   123  			//有问题但是不处理
   124  			println("关闭文件时 Close() ", err)
   125  		}
   126  	}
   127  	return nil
   128  }