代码拉取完成,页面将自动刷新
package rlog
import (
"context"
"fmt"
"gitee.com/ruige_fun/util/rwheel"
"io"
"os"
"path"
"runtime"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/logrusorgru/aurora/v4"
)
const (
LogFileModel = 0660
DefaultLogFileMaxSize = 1024 * 1024 * 10
)
const (
tagDebug = "debug "
tagInfo = "info "
tagSuccess = "succ "
tagWarn = "warn "
tagError = "error "
tagPanic = "panic "
tagPrint = "print "
tagMust = "must "
tagMustOnly = "only "
)
// NewLogger 新建一个日志管理器
// windows彩色日志:import "github.com/mattn/go-colorable" 参数传 colorable.NewColorableStdout()
func NewLogger(stdout io.Writer) RLogger {
l := &_logger{
_runtimeCaller: 2,
_consoleWriter: stdout,
_consoleLevel: LevelDebug,
_fileLevel: LevelDebug,
_curFileSize: 0,
_maxFileSize: DefaultLogFileMaxSize,
_oldLogToZip: false,
_isFullTextStaining: false,
_lock: sync.Mutex{},
_tempContent: make([]byte, 0, DefaultLogFileMaxSize+10),
}
rwheel.AppendToTimeWheel(&rwheel.TimeWheel{
IntervalMilli: 1000,
Ctx: context.TODO(),
Func: l.autoCreateLogFile,
IsLoop: true,
}, true)
return l
}
type _logger struct {
_runtimeCaller int //日志
_consoleWriter io.Writer //控制台输出
_file *os.File //日志文件输出
_filepath string //日志文件地址
_consoleLevel Level //控制台输出等级
_fileLevel Level //文件输出等级
_curFileSize int64 //当前日志文件大小
_maxFileSize int64 //最大日志文件大小
_oldLogToZip bool //旧日志文件是否压缩成zip文件
_isFullTextStaining bool //是否全文着色输出,false仅tag着色。
_lock sync.Mutex //锁
_tempContent []byte //缓存日志文件
_autoDeleteOldLogFile uint //自动删除多少天以前的日志,0则不删除
}
func (l *_logger) autoCreateLogFile(ctx context.Context) {
if l == nil || l._filepath == "" {
return
}
l._lock.Lock()
if len(l._tempContent) > 0 {
size, _ := l._file.Write(l._tempContent)
l._curFileSize += int64(size)
atomic.AddInt64(&waitWriteLogCount, int64(-len(l._tempContent)))
l._tempContent = make([]byte, 0, DefaultLogFileMaxSize+10)
}
if l._curFileSize >= l._maxFileSize {
atomic.AddInt64(&waitWriteLogCount, 1)
if l._file != nil {
_ = l._file.Close()
l._file = nil
var err error
if l._oldLogToZip {
err = zipSaveAs(l._filepath, fmt.Sprint(l._filepath, ".", time.Now().Format("20060102_150405Z0700"), ".zip"), true)
} else {
err = os.Rename(l._filepath, fmt.Sprint(l._filepath, ".", time.Now().Format("20060102_150405Z0700"), path.Ext(l._filepath)))
}
if err == nil {
file, err := os.OpenFile(l._filepath, os.O_CREATE|os.O_WRONLY, LogFileModel)
if err == nil {
l._file = file
l._curFileSize = 0
fmt.Println(aurora.Green(fmt.Sprint("创建新的日志文件成功:", l._file.Name())))
} else {
fmt.Println(aurora.Red(fmt.Sprint("创建新的日志文件失败:", err)))
}
} else {
fmt.Println(aurora.Red(fmt.Sprint("重命名旧日志文件失败:", err)))
}
} else if l._filepath != "" {
l.initCreateFile()
}
if l._autoDeleteOldLogFile > 0 {
//自动删除旧日志文件
logDir := path.Dir(l._file.Name())
allList, _ := os.ReadDir(logDir)
oldTimeLimit := time.Now().Unix() - int64(l._autoDeleteOldLogFile*86400)
for _, d := range allList {
if d.IsDir() {
continue
}
base := path.Base(l._file.Name())
if strings.HasPrefix(d.Name(), base) && d.Name() != base {
if info, err := d.Info(); err == nil {
if info.ModTime().Unix() < oldTimeLimit {
fmt.Println(aurora.Red(fmt.Sprint("自动清理旧日志文件:", os.Remove(path.Join(logDir, info.Name())))))
}
}
}
}
}
atomic.AddInt64(&waitWriteLogCount, -1)
}
l._lock.Unlock()
}
func (l *_logger) initCreateFile() {
if l._file != nil && l._filepath == "" {
return
}
atomic.AddInt64(&waitWriteLogCount, 1)
defer atomic.AddInt64(&waitWriteLogCount, -1)
fmt.Println("初始化创建日志文件:", l._filepath)
l._lock.Lock()
defer l._lock.Unlock()
_ = os.MkdirAll(path.Dir(strings.ReplaceAll(l._filepath, `\`, "/")), LogFileModel)
stat, err := os.Stat(l._filepath)
if err != nil {
l._curFileSize = 0
if strings.Contains(err.Error(), "cannot find") ||
strings.Contains(err.Error(), "no such") {
//文件不存在
file, err := os.OpenFile(l._filepath, os.O_WRONLY|os.O_CREATE, LogFileModel)
if err != nil {
fmt.Println(aurora.Red(fmt.Sprint("创建新的日志文件失败:", err)))
return
}
l._file = file
} else {
fmt.Println(aurora.Red(fmt.Sprint("读取新的日志文件失败:", err)))
}
} else {
file, err := os.OpenFile(l._filepath, os.O_WRONLY|os.O_APPEND, LogFileModel)
if err != nil {
fmt.Println(aurora.Red(fmt.Sprint("创建新的日志文件失败:", err)))
}
l._file = file
l._curFileSize = stat.Size()
}
}
func (l *_logger) prefix() string {
now := time.Now()
year, month, day := now.Date()
hour, min, sec := now.Clock()
mill := now.UnixMilli() % 1000
_, file, line, _ := runtime.Caller(l._runtimeCaller)
if projectDirLength == 0 || projectDirLength > len(file) {
return fmt.Sprintf("%4d/%02d/%02d·%02d:%02d:%02d.%03d %v:%v :", year, int(month), day, hour, min, sec, mill, path.Base(file), line)
} else {
return fmt.Sprintf("%4d/%02d/%02d·%02d:%02d:%02d.%03d %v:%v :", year, int(month), day, hour, min, sec, mill, file[projectDirLength:], line)
}
}
func (l *_logger) writeFile(content []byte) {
l._lock.Lock()
atomic.AddInt64(&waitWriteLogCount, int64(len(content)))
l._tempContent = append(l._tempContent, content...)
l._lock.Unlock()
}
func (l *_logger) Print(a ...any) {
content := []byte(tagPrint + l.prefix() + fmt.Sprint(a...))
if l._fileLevel < LevelDisable && l._file != nil {
go l.writeFile(content)
}
if l._consoleLevel < LevelDisable && l._consoleWriter != nil {
_, _ = l._consoleWriter.Write(content)
}
}
func (l *_logger) Println(a ...any) {
content := []byte(tagPrint + l.prefix() + fmt.Sprintln(a...))
if l._fileLevel < LevelDisable && l._file != nil {
go l.writeFile(content)
}
if l._consoleLevel < LevelDisable && l._consoleWriter != nil {
_, _ = l._consoleWriter.Write(content)
}
}
func (l *_logger) Printf(format string, a ...any) {
content := []byte(tagPrint + l.prefix() + fmt.Sprintf(format, a...))
if l._fileLevel < LevelDisable && l._file != nil {
go l.writeFile(content)
}
if l._consoleLevel < LevelDisable && l._consoleWriter != nil {
_, _ = l._consoleWriter.Write(content)
}
}
func (l *_logger) Debug(a ...any) {
content := l.prefix() + fmt.Sprintln(a...)
if l._fileLevel <= LevelDebug && l._file != nil {
go l.writeFile([]byte(tagDebug + content))
}
if l._consoleLevel <= LevelDebug && l._consoleWriter != nil {
if l._isFullTextStaining {
_, _ = l._consoleWriter.Write([]byte(aurora.Blue(tagDebug + content).String()))
} else {
_, _ = l._consoleWriter.Write([]byte(aurora.Blue(tagDebug).String() + content))
}
}
}
func (l *_logger) Info(a ...any) {
content := l.prefix() + fmt.Sprintln(a...)
if l._fileLevel <= LevelInfo && l._file != nil {
go l.writeFile([]byte(tagInfo + content))
}
if l._consoleLevel <= LevelInfo && l._consoleWriter != nil {
if l._isFullTextStaining {
_, _ = l._consoleWriter.Write([]byte(aurora.Cyan(tagInfo + content).String()))
} else {
_, _ = l._consoleWriter.Write([]byte(aurora.Cyan(tagInfo).String() + content))
}
}
}
func (l *_logger) Success(a ...any) {
content := l.prefix() + fmt.Sprintln(a...)
if l._fileLevel <= LevelSuccess && l._file != nil {
go l.writeFile([]byte(tagSuccess + content))
}
if l._consoleLevel <= LevelSuccess && l._consoleWriter != nil {
if l._isFullTextStaining {
_, _ = l._consoleWriter.Write([]byte(aurora.Green(tagSuccess + content).String()))
} else {
_, _ = l._consoleWriter.Write([]byte(aurora.Green(tagSuccess).String() + content))
}
}
}
func (l *_logger) Warn(a ...any) {
content := l.prefix() + fmt.Sprintln(a...)
if l._fileLevel <= LevelWarn && l._file != nil {
go l.writeFile([]byte(tagWarn + content))
}
if l._consoleLevel <= LevelWarn && l._consoleWriter != nil {
if l._isFullTextStaining {
_, _ = l._consoleWriter.Write([]byte(aurora.Yellow(tagWarn + content).String()))
} else {
_, _ = l._consoleWriter.Write([]byte(aurora.Yellow(tagWarn).String() + content))
}
}
}
func (l *_logger) Error(a ...any) {
content := l.prefix() + fmt.Sprintln(a...)
if l._fileLevel <= LevelError && l._file != nil {
go l.writeFile([]byte(tagError + content))
}
if l._consoleLevel <= LevelError && l._consoleWriter != nil {
if l._isFullTextStaining {
_, _ = l._consoleWriter.Write([]byte(aurora.Red(tagError + content).String()))
} else {
_, _ = l._consoleWriter.Write([]byte(aurora.Red(tagError).String() + content))
}
}
}
func (l *_logger) Panic(a ...any) {
content := l.prefix() + fmt.Sprintln(a...)
if l._fileLevel <= LevelPanic && l._file != nil {
go l.writeFile([]byte(tagPanic + content))
}
if l._consoleLevel <= LevelPanic && l._consoleWriter != nil {
if l._isFullTextStaining {
_, _ = l._consoleWriter.Write([]byte(aurora.Magenta(tagPanic + content).String()))
} else {
_, _ = l._consoleWriter.Write([]byte(aurora.Magenta(tagPanic).String() + content))
}
}
}
func (l *_logger) PrintlnConsoleMust(a ...any) {
content := []byte(tagMust + l.prefix() + fmt.Sprintln(a...))
if l._fileLevel < LevelDisable && l._file != nil {
go l.writeFile(content)
}
if l._consoleWriter != nil {
_, _ = l._consoleWriter.Write(content)
}
}
func (l *_logger) PrintlnFileMust(a ...any) {
content := []byte(tagMust + l.prefix() + fmt.Sprintln(a...))
if l._file != nil {
go l.writeFile(content)
}
if l._consoleLevel < LevelDisable && l._consoleWriter != nil {
_, _ = l._consoleWriter.Write(content)
}
}
func (l *_logger) PrintlnConsoleMustOnly(a ...any) {
content := []byte(tagMustOnly + l.prefix() + fmt.Sprintln(a...))
if l._consoleWriter != nil {
_, _ = l._consoleWriter.Write(content)
}
}
func (l *_logger) PrintlnFileMustOnly(a ...any) {
content := []byte(tagMustOnly + l.prefix() + fmt.Sprintln(a...))
if l._file != nil {
go l.writeFile(content)
}
}
func (l *_logger) SetLogFilePath(filepath string, oldLogToZip bool) {
l._oldLogToZip = oldLogToZip
l._filepath = strings.ReplaceAll(filepath, `\`, `/`) //替换成统一的路径斜线
l.initCreateFile()
}
func (l *_logger) SetConsoleLevel(level Level) {
l._consoleLevel = level
}
func (l *_logger) SetFileLevel(level Level) {
l._fileLevel = level
}
func (l *_logger) SetFullTextStaining(full bool) {
l._isFullTextStaining = full
}
func (l *_logger) SetAutoDeleteOldLogFile(day uint) {
l._autoDeleteOldLogFile = day
}
func (l *_logger) setRuntimeCaller(skip int) {
l._runtimeCaller = skip
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。