lxutils/lxlog/lxlog.go
liuchangshun 2937bf6579 xxx
2023-11-22 08:28:52 +08:00

280 lines
5.9 KiB
Go

package lxlog
import (
"fmt"
"os"
"runtime"
"strconv"
"time"
)
// 异步写日志
var MyLog *FileLog
const (
LogSplitTypeHour = iota
LogSplitTypeSize
logPath = "myLog"
logName = "myLog"
chanSize = 5000
)
type FileLog struct {
logPath string
logName string
file *os.File //普通日志
warnFile *os.File //错误日志 级别低
logDataChan chan *LogData
logSplitType int //分割类型
logSplitSize int64 //分割体积
lastSplitHour int //分割时间
}
type LogData struct {
Message string
TimeStr string
LevelStr string
IsWarn bool
File string
}
// _ = tools.InitLog()
func InitLog() (log *FileLog) {
config := make(map[string]string, 8)
config["log_path"] = "."
config["log_name"] = "server"
config["log_chan_size"] = "50000" //chan size 可以不用
config["log_split_type"] = "size"
config["log_split_size"] = strconv.Itoa(1024 * 1024 * 1024) // 1g
log, err := NewFileLog(config)
if err != nil {
panic("init log err")
}
MyLog = log
return log
}
func NewFileLog(config map[string]string) (logFile *FileLog, err error) {
var logSplitType = LogSplitTypeSize
var logSplitSize int64
splitType, ok := config["log_split_type"]
if !ok {
splitType = "hour"
} else {
if splitType == "size" {
splitSize, ok := config["log_split_size"]
if !ok {
splitSize = "104857600" //100M 以文字来讲很多了
}
logSplitSize, err = strconv.ParseInt(splitSize, 10, 64)
if err != nil {
logSplitSize = 104857600
}
logSplitType = LogSplitTypeSize
} else {
logSplitType = LogSplitTypeHour
}
}
//打开日志文件
exist, err := PathIsExists(logPath)
if err != nil {
fmt.Printf("get dir error![%v]\n", err)
return
}
if !exist {
err = os.Mkdir(logPath, os.ModePerm)
if err != nil {
fmt.Printf("mkdir failed![%v]\n", err)
return
} else {
fmt.Printf("mkdir success!\n")
}
}
//正常日志
fileName := fmt.Sprintf("%s/%s.log", logPath, logName)
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
//错误日志
fileNameWarn := fmt.Sprintf("%s/%s.log.err", logPath, logName)
fileWarn, err := os.OpenFile(fileNameWarn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
return
}
logFile = &FileLog{
logPath: logPath,
logName: logName,
logDataChan: make(chan *LogData, chanSize),
file: file,
warnFile: fileWarn,
logSplitType: logSplitType,
logSplitSize: logSplitSize,
lastSplitHour: time.Now().Hour(),
}
go logFile.writeLogBackGround()
return
}
// 判断文件夹是否存在
func PathIsExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
func (f *FileLog) Info(message string) {
_, file, line, _ := runtime.Caller(1)
fi := file + ":" + strconv.Itoa(line)
f.print(message, "info", fi)
}
func (f *FileLog) Debug(message string) {
_, file, line, _ := runtime.Caller(1)
fi := file + ":" + strconv.Itoa(line)
f.print(message, "debug", fi)
}
func (f *FileLog) Warn(message string) {
_, file, line, _ := runtime.Caller(1)
fi := file + ":" + strconv.Itoa(line)
f.print(message, "warn", fi)
}
func (f *FileLog) Error(message string) {
_, file, line, _ := runtime.Caller(1)
fi := file + ":" + strconv.Itoa(line)
f.print(message, "error", fi)
}
func (f *FileLog) print(message, Type string, file string) {
isWarn := false
if Type == "error" {
isWarn = true
}
msg := &LogData{
Message: message,
TimeStr: time.Now().Format("2006-01-02 15:04:05"),
LevelStr: Type,
IsWarn: isWarn,
File: file,
}
// 怕chan满了插不进去
select {
case f.logDataChan <- msg:
default:
}
}
func (f *FileLog) writeLogBackGround() {
for logData := range f.logDataChan {
var file = f.file
if logData.IsWarn {
file = f.warnFile
}
f.checkSplitFile(logData.IsWarn) // 检查文件分割类型
fmt.Fprintf(file, "%s %s %s %s\n", logData.TimeStr, logData.LevelStr, logData.Message, logData.File)
}
}
func (f *FileLog) checkSplitFile(isWarn bool) {
if f.logSplitType == LogSplitTypeHour {
f.splitHour(isWarn)
return
}
f.splitSize(isWarn)
}
// 根据时间切割
func (f *FileLog) splitHour(isWarn bool) {
now := time.Now()
hour := now.Hour()
if hour == f.lastSplitHour {
return
}
f.lastSplitHour = hour
var backupFileName string
var fileName string
if isWarn {
backupFileName = fmt.Sprintf("%s/%s.log.err_%s", f.logPath, f.logName, now.Format("20060102150405"))
fileName = fmt.Sprintf("%s/%s.log.err", f.logPath, f.logName)
} else {
backupFileName = fmt.Sprintf("%s/%s.log_%s", f.logPath, f.logName, now.Format("20060102150405"))
fileName = fmt.Sprintf("%s/%s.log", f.logPath, f.logName)
}
file := f.file
if isWarn {
file = f.warnFile
}
file.Close()
os.Rename(fileName, backupFileName)
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
return
}
if isWarn {
f.warnFile = file
} else {
f.file = file
}
}
// 根据文件大小来分割
func (f *FileLog) splitSize(isWarn bool) {
file := f.file
if isWarn {
file = f.warnFile
}
fileInfo, err := file.Stat() // 可以得到文件的参数
if err != nil {
return
}
fileSize := fileInfo.Size()
if fileSize <= f.logSplitSize {
return
}
var backupFileName string
var fileName string
now := time.Now()
if isWarn {
backupFileName = fmt.Sprintf("%s/%s.log.err_%s", f.logPath, f.logName, now.Format("20060102150405"))
fileName = fmt.Sprintf("%s/%s.log.err", f.logPath, f.logName)
} else {
backupFileName = fmt.Sprintf("%s/%s.log_%s", f.logPath, f.logName, now.Format("20060102150405"))
fileName = fmt.Sprintf("%s/%s.log", f.logPath, f.logName)
}
file.Close()
os.Rename(fileName, backupFileName)
file, err = os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
return
}
if isWarn {
f.warnFile = file
} else {
f.file = file
}
}