writer.go 4.4 KB
Newer Older
Y
Your Name 已提交
1
package gokulog
E
eoLinker API Management 已提交
2 3 4 5 6 7 8 9 10 11 12 13

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
)
Y
Your Name 已提交
14

Y
Your Name 已提交
15
//MaxBufferd 最大缓存数值
Y
Your Name 已提交
16 17 18
const MaxBufferd = 1024 * 500

var (
E
eoLinker API Management 已提交
19 20 21 22 23 24
	bufferPool = &sync.Pool{
		New: func() interface{} {
			return new(bytes.Buffer)
		},
	}
)
Y
Your Name 已提交
25

Y
Your Name 已提交
26
//FileWriterByPeriod 文件输出对象
E
eoLinker API Management 已提交
27
type FileWriterByPeriod struct {
Y
Your Name 已提交
28 29 30 31 32 33 34 35 36
	wC         chan *bytes.Buffer
	dir        string
	file       string
	period     LogPeriod
	enable     bool
	cancelFunc context.CancelFunc
	locker     sync.Mutex
	wg         sync.WaitGroup
	expire     time.Duration
E
eoLinker API Management 已提交
37 38
}

Y
Your Name 已提交
39
//NewFileWriteBytePeriod 创建文件输出对象
E
eoLinker API Management 已提交
40
func NewFileWriteBytePeriod() *FileWriterByPeriod {
Y
Your Name 已提交
41 42 43 44
	w := &FileWriterByPeriod{
		locker: sync.Mutex{},
		wg:     sync.WaitGroup{},
		enable: false,
E
eoLinker API Management 已提交
45 46 47 48
	}

	return w
}
Y
Your Name 已提交
49
func (w *FileWriterByPeriod) getExpire() time.Duration {
E
eoLinker API Management 已提交
50
	w.locker.Lock()
Y
Your Name 已提交
51
	expire := w.expire
E
eoLinker API Management 已提交
52 53 54
	w.locker.Unlock()
	return expire
}
Y
Your Name 已提交
55 56

//Set 设置对象信息
Y
Your Name 已提交
57 58
func (w *FileWriterByPeriod) Set(dir, file string, period LogPeriod, expire time.Duration) {
	fileName := strings.TrimSuffix(file, ".log")
E
eoLinker API Management 已提交
59 60 61 62 63 64 65 66

	w.locker.Lock()
	w.file = fileName
	w.dir = dir
	w.period = period
	w.expire = expire
	w.locker.Unlock()
}
Y
Your Name 已提交
67 68

//Open 打开文件
Y
Your Name 已提交
69
func (w *FileWriterByPeriod) Open() {
E
eoLinker API Management 已提交
70
	w.locker.Lock()
Y
Your Name 已提交
71
	defer w.locker.Unlock()
E
eoLinker API Management 已提交
72

Y
Your Name 已提交
73
	if w.enable {
E
eoLinker API Management 已提交
74 75 76 77 78
		return
	}

	ctx, cancel := context.WithCancel(context.Background())
	w.cancelFunc = cancel
Y
Your Name 已提交
79
	w.wC = make(chan *bytes.Buffer, 100)
E
eoLinker API Management 已提交
80 81 82 83
	w.wg.Add(1)
	w.enable = true
	go w.do(ctx)
}
Y
Your Name 已提交
84 85

//Close 关闭对象
Y
Your Name 已提交
86
func (w *FileWriterByPeriod) Close() {
E
eoLinker API Management 已提交
87 88 89

	isClose := false
	w.locker.Lock()
Y
Your Name 已提交
90
	if !w.enable {
E
eoLinker API Management 已提交
91 92 93 94
		w.locker.Unlock()
		return
	}

Y
Your Name 已提交
95
	if w.cancelFunc != nil {
E
eoLinker API Management 已提交
96 97 98 99 100 101
		isClose = true
		w.cancelFunc()
		w.cancelFunc = nil
	}
	w.enable = false
	w.locker.Unlock()
Y
Your Name 已提交
102
	if isClose {
E
eoLinker API Management 已提交
103 104 105 106 107 108
		w.wg.Wait()
	}

}
func (w *FileWriterByPeriod) Write(p []byte) (n int, err error) {

Y
Your Name 已提交
109
	l := len(p)
E
eoLinker API Management 已提交
110
	if !w.enable {
Y
Your Name 已提交
111
		return l, nil
E
eoLinker API Management 已提交
112 113 114 115 116
	}
	buffer := bufferPool.Get().(*bytes.Buffer)
	buffer.Reset()
	buffer.Write(p)

Y
Your Name 已提交
117 118
	w.wC <- buffer
	return l, nil
E
eoLinker API Management 已提交
119 120
}

Y
Your Name 已提交
121
func (w *FileWriterByPeriod) do(ctx context.Context) {
E
eoLinker API Management 已提交
122
	w.initFile()
Y
Your Name 已提交
123 124 125
	f, lastTag, e := w.openFile()
	if e != nil {
		fmt.Printf("open log file:%s\n", e.Error())
E
eoLinker API Management 已提交
126 127 128
		return
	}

Y
Your Name 已提交
129 130
	buf := bufio.NewWriter(f)
	t := time.NewTicker(time.Second * 5)
E
eoLinker API Management 已提交
131
	defer t.Stop()
Y
Your Name 已提交
132
	tflusth := time.NewTimer(time.Second)
E
eoLinker API Management 已提交
133

Y
Your Name 已提交
134
	for {
E
eoLinker API Management 已提交
135 136 137
		select {
		case <-ctx.Done():
			{
Y
Your Name 已提交
138 139
				for len(w.wC) > 0 {
					p := <-w.wC
E
eoLinker API Management 已提交
140 141 142 143 144 145 146 147 148 149 150 151
					buf.Write(p.Bytes())
					bufferPool.Put(p)
				}
				buf.Flush()
				f.Close()
				t.Stop()
				w.wg.Done()
				return
			}

		case <-t.C:
			{
Y
Your Name 已提交
152
				if buf.Buffered() > 0 {
E
eoLinker API Management 已提交
153 154 155
					buf.Flush()
					tflusth.Reset(time.Second)
				}
Y
Your Name 已提交
156
				if lastTag != w.timeTag(time.Now()) {
E
eoLinker API Management 已提交
157 158 159

					f.Close()
					w.history(lastTag)
Y
Your Name 已提交
160 161
					fnew, tag, err := w.openFile()
					if err != nil {
E
eoLinker API Management 已提交
162 163 164
						return
					}
					lastTag = tag
Y
Your Name 已提交
165
					f = fnew
E
eoLinker API Management 已提交
166 167 168 169 170 171 172 173
					buf.Reset(f)

					go w.dropHistory()
				}

			}
		case <-tflusth.C:
			{
Y
Your Name 已提交
174
				if buf.Buffered() > 0 {
E
eoLinker API Management 已提交
175 176 177 178
					buf.Flush()
				}
				tflusth.Reset(time.Second)
			}
Y
Your Name 已提交
179 180 181 182 183 184 185 186
		case p := <-w.wC:
			{
				buf.Write(p.Bytes())
				bufferPool.Put(p)
				if buf.Buffered() > MaxBufferd {
					buf.Flush()
				}
				tflusth.Reset(time.Second)
E
eoLinker API Management 已提交
187 188 189 190 191 192 193
			}
		}
	}
}
func (w *FileWriterByPeriod) timeTag(t time.Time) string {

	w.locker.Lock()
Y
Your Name 已提交
194
	tag := t.Format(w.period.FormatLayout())
E
eoLinker API Management 已提交
195 196 197 198 199
	w.locker.Unlock()
	return tag
}
func (w *FileWriterByPeriod) history(tag string) {

Y
Your Name 已提交
200 201 202
	path := filepath.Join(w.dir, fmt.Sprintf("%s.log", w.file))
	histroy := filepath.Join(w.dir, fmt.Sprintf("%s-%s.log", w.file, tag))
	_ = os.Rename(path, histroy)
E
eoLinker API Management 已提交
203 204

}
Y
Your Name 已提交
205 206
func (w *FileWriterByPeriod) dropHistory() {
	expire := w.getExpire()
E
eoLinker API Management 已提交
207
	expireTime := time.Now().Add(- expire)
Y
Your Name 已提交
208
	pathPatten := filepath.Join(w.dir, fmt.Sprintf("%s-*", w.file))
E
eoLinker API Management 已提交
209
	files, err := filepath.Glob(pathPatten)
Y
Your Name 已提交
210 211 212
	if err == nil {
		for _, f := range files {
			if info, e := os.Stat(f); e == nil {
E
eoLinker API Management 已提交
213

Y
Your Name 已提交
214 215
				if expireTime.After(info.ModTime()) {
					_ = os.Remove(f)
E
eoLinker API Management 已提交
216 217 218 219 220
				}
			}
		}
	}
}
Y
Your Name 已提交
221 222 223 224 225 226 227 228
func (w *FileWriterByPeriod) initFile() {
	_ = os.MkdirAll(w.dir, os.ModePerm)
	path := filepath.Join(w.dir, fmt.Sprintf("%s.log", w.file))
	nowTag := w.timeTag(time.Now())
	if info, e := os.Stat(path); e == nil {

		timeTag := w.timeTag(info.ModTime())
		if timeTag != nowTag {
E
eoLinker API Management 已提交
229 230 231 232 233 234 235 236
			w.history(timeTag)
		}
	}

	w.dropHistory()

}

Y
Your Name 已提交
237 238 239 240
func (w *FileWriterByPeriod) openFile() (*os.File, string, error) {
	path := filepath.Join(w.dir, fmt.Sprintf("%s.log", w.file))
	nowTag := w.timeTag(time.Now())
	f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
E
eoLinker API Management 已提交
241

Y
Your Name 已提交
242 243
	if err != nil {
		return nil, "", err
E
eoLinker API Management 已提交
244
	}
Y
Your Name 已提交
245
	return f, nowTag, err
E
eoLinker API Management 已提交
246

Y
Your Name 已提交
247
}