代码拉取完成,页面将自动刷新
package alog
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"sync"
"time"
)
var (
lfs = map[string]*LogFile{}
lfsLock sync.Mutex
)
const (
bufferSize = 4194304 // 4M Byte
flushTimeout = 1 * time.Second
keepDays = 7 // TODO conf
rotation = "daily" // TODO conf
)
type LogFile struct {
path string
file *os.File
buf []byte
size int64
bufferC chan []byte
flushC chan bool
reopenC chan bool
closeC chan bool
// logrotate rule
rule RotateRule
}
// 创建 LogFile
func CreateLogFile(conf *LogConf) *LogFile {
lfsLock.Lock()
defer lfsLock.Unlock()
if lf, ok := lfs[conf.LogFile]; ok {
return lf
}
basePath := filepath.Dir(conf.LogFile)
if _, err := os.Stat(basePath); err != nil {
if err = os.MkdirAll(basePath, 0755); err != nil {
log.Fatalf("Mkdir %s err: %v", basePath, err)
}
}
f, err := os.OpenFile(conf.LogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Fatalf("Open file %s err: %v", conf.LogFile, err)
}
lf := &LogFile{
path: conf.LogFile,
file: f,
buf: make([]byte, bufferSize),
size: 0,
bufferC: make(chan []byte, runtime.NumCPU()),
flushC: make(chan bool, 1),
reopenC: make(chan bool, 1),
closeC: make(chan bool, 1),
}
// TODO SizeRotateRule
// if conf.Rotation == "daily" {
lf.rule = CreateDailyRotateRule(conf.LogFile, int(conf.KeepDays))
// }
lfs[conf.LogFile] = lf
go lf.loop()
return lf
}
// 重新打开所有 LogFile
func ReopenLogFiles() {
lfsLock.Lock()
defer lfsLock.Unlock()
for _, lf := range lfs {
lf.Reopen()
}
}
// 关闭所有 LogFile
func CloseLogFiles() {
lfsLock.Lock()
defer lfsLock.Unlock()
for _, lf := range lfs {
lf.closeC <- true
delete(lfs, lf.path)
}
}
func (lf *LogFile) rotate() {
// rename current file to backup file
backupFileName := lf.rule.BackupFileName()
os.Rename(lf.path, backupFileName)
// delete outdated files
deleteFiles := lf.rule.OutdatedFiles()
for _, file := range deleteFiles {
os.Remove(file)
}
lf.Reopen()
}
func (lf *LogFile) flush() {
n, err := lf.file.Write(lf.buf[:lf.size])
if err != nil {
fmt.Printf("Write File failed, write %d, expected: %d, err: %v\n", n, len(lf.buf), err)
}
lf.size = 0
// TODO SizeRotateRule
if lf.rule.ShallRotate(0) {
lf.rotate()
lf.rule.MarkRotated()
}
}
func (lf *LogFile) write(b []byte) {
length := len(b)
if int(lf.size)+length > len(lf.buf) {
lf.flush()
}
copy(lf.buf[lf.size:], b)
lf.size += int64(length)
}
func (lf *LogFile) loop() {
ti := time.NewTimer(flushTimeout)
defer func() {
ti.Stop()
lf.flush()
}()
for {
select {
case b := <-lf.bufferC:
lf.write(b)
case <-lf.flushC:
lf.flush()
ti = time.NewTimer(flushTimeout)
case <-lf.reopenC:
lf.flush()
ti = time.NewTimer(flushTimeout)
lf.file.Close()
f, err := os.OpenFile(lf.path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("Open file %s err: %v\n", lf.path, err)
return
}
lf.file = f
case <-ti.C:
lf.flush()
ti = time.NewTimer(flushTimeout)
case <-lf.closeC:
return
}
}
}
// 向 LogFile 中写入内容
func (lf *LogFile) Write(b []byte) {
lf.bufferC <- b
}
// 将 LogFile 中的内容刷入文件
func (lf *LogFile) Flush() {
lf.flushC <- true
}
// 重新打开 LogFile,用于日志 rotate 使用
func (lf *LogFile) Reopen() {
lf.reopenC <- true
}
// 停止 LogFile
func (lf *LogFile) Close() {
lf.closeC <- true
lfsLock.Lock()
defer lfsLock.Unlock()
delete(lfs, lf.path)
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。