package loggergit
import (github
"fmt"測試
"log"spa
"os"debug
"runtime"日誌
"strconv"code
"sync"orm
"time"string
)it
const (
_VER string = "1.0.0"
)
type LEVEL int32
var logLevel LEVEL = 1
var maxFileSize int64
var maxFileCount int32
var dailyRolling bool = true
var consoleAppender bool = true
var RollingFile bool = false
var logObj *_FILE
const DATEFORMAT = "2006-01-02"
type UNIT int64
const (
_ = iota
KB UNIT = 1 << (iota * 10)
MB
GB
TB
)
const (
ALL LEVEL = iota
DEBUG
INFO
WARN
ERROR
FATAL
OFF
)
type _FILE struct {
dir string
filename string
_suffix int
isCover bool
_date *time.Time
mu *sync.RWMutex
logfile *os.File
lg *log.Logger
}
func SetConsole(isConsole bool) {
consoleAppender = isConsole
}
func SetLevel(_level LEVEL) {
logLevel = _level
}
func SetRollingFile(fileDir, fileName string, maxNumber int32, maxSize int64, _unit UNIT) {
maxFileCount = maxNumber
maxFileSize = maxSize * int64(_unit)
RollingFile = true
dailyRolling = false
logObj = &_FILE{dir: fileDir, filename: fileName, isCover: false, mu: new(sync.RWMutex)}
logObj.mu.Lock()
defer logObj.mu.Unlock()
for i := 1; i <= int(maxNumber); i++ {
if isExist(fileDir + "/" + fileName + "." + strconv.Itoa(i)) {
logObj._suffix = i
} else {
break
}
}
if !logObj.isMustRename() {
logObj.logfile, _ = os.OpenFile(fileDir+"/"+fileName, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0)
logObj.lg = log.New(logObj.logfile, "\n", log.Ldate|log.Ltime|log.Lshortfile)
} else {
logObj.rename()
}
go fileMonitor()
}
func SetRollingDaily(fileDir, fileName string) {
RollingFile = false
dailyRolling = true
t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))
logObj = &_FILE{dir: fileDir, filename: fileName, _date: &t, isCover: false, mu: new(sync.RWMutex)}
logObj.mu.Lock()
defer logObj.mu.Unlock()
if !logObj.isMustRename() {
logObj.logfile, _ = os.OpenFile(fileDir+"/"+fileName, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0)
logObj.lg = log.New(logObj.logfile, "\n", log.Ldate|log.Ltime|log.Lshortfile)
} else {
logObj.rename()
}
}
func console(s ...interface{}) {
if consoleAppender {
_, file, line, _ := runtime.Caller(2)
short := file
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
short = file[i+1:]
break
}
}
file = short
log.Println(file+":"+strconv.Itoa(line), s)
}
}
func catchError() {
if err := recover(); err != nil {
log.Println("err", err)
}
}
func Debug(v ...interface{}) {
if dailyRolling {
fileCheck()
}
defer catchError()
logObj.mu.RLock()
defer logObj.mu.RUnlock()
if logLevel <= DEBUG {
logObj.lg.Output(2, fmt.Sprintln("debug", v))
console("debug", v)
}
}
func Info(v ...interface{}) {
if dailyRolling {
fileCheck()
}
defer catchError()
logObj.mu.RLock()
defer logObj.mu.RUnlock()
if logLevel <= INFO {
logObj.lg.Output(2, fmt.Sprintln("info", v))
console("info", v)
}
}
func Warn(v ...interface{}) {
if dailyRolling {
fileCheck()
}
defer catchError()
logObj.mu.RLock()
defer logObj.mu.RUnlock()
if logLevel <= WARN {
logObj.lg.Output(2, fmt.Sprintln("warn", v))
console("warn", v)
}
}
func Error(v ...interface{}) {
if dailyRolling {
fileCheck()
}
defer catchError()
logObj.mu.RLock()
defer logObj.mu.RUnlock()
if logLevel <= ERROR {
logObj.lg.Output(2, fmt.Sprintln("error", v))
console("error", v)
}
}
func Fatal(v ...interface{}) {
if dailyRolling {
fileCheck()
}
defer catchError()
logObj.mu.RLock()
defer logObj.mu.RUnlock()
if logLevel <= FATAL {
logObj.lg.Output(2, fmt.Sprintln("fatal", v))
console("fatal", v)
}
}
func (f *_FILE) isMustRename() bool {
if dailyRolling {
t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))
if t.After(*f._date) {
return true
}
} else {
if maxFileCount > 1 {
if fileSize(f.dir+"/"+f.filename) >= maxFileSize {
return true
}
}
}
return false
}
func (f *_FILE) rename() {
if dailyRolling {
fn := f.dir + "/" + f.filename + "." + f._date.Format(DATEFORMAT)
if !isExist(fn) && f.isMustRename() {
if f.logfile != nil {
f.logfile.Close()
}
err := os.Rename(f.dir+"/"+f.filename, fn)
if err != nil {
f.lg.Println("rename err", err.Error())
}
t, _ := time.Parse(DATEFORMAT, time.Now().Format(DATEFORMAT))
f._date = &t
f.logfile, _ = os.Create(f.dir + "/" + f.filename)
f.lg = log.New(logObj.logfile, "\n", log.Ldate|log.Ltime|log.Lshortfile)
}
} else {
f.coverNextOne()
}
}
func (f *_FILE) nextSuffix() int {
return int(f._suffix%int(maxFileCount) + 1)
}
func (f *_FILE) coverNextOne() {
f._suffix = f.nextSuffix()
if f.logfile != nil {
f.logfile.Close()
}
if isExist(f.dir + "/" + f.filename + "." + strconv.Itoa(int(f._suffix))) {
os.Remove(f.dir + "/" + f.filename + "." + strconv.Itoa(int(f._suffix)))
}
os.Rename(f.dir+"/"+f.filename, f.dir+"/"+f.filename+"."+strconv.Itoa(int(f._suffix)))
f.logfile, _ = os.Create(f.dir + "/" + f.filename)
f.lg = log.New(logObj.logfile, "\n", log.Ldate|log.Ltime|log.Lshortfile)
}
func fileSize(file string) int64 {
fmt.Println("fileSize", file)
f, e := os.Stat(file)
if e != nil {
fmt.Println(e.Error())
return 0
}
return f.Size()
}
func isExist(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}
func fileMonitor() {
timer := time.NewTicker(1 * time.Second)
for {
select {
case <-timer.C:
fileCheck()
}
}
}
func fileCheck() {
defer func() {
if err := recover(); err != nil {
log.Println(err)
}
}()
if logObj != nil && logObj.isMustRename() {
logObj.mu.Lock()
defer logObj.mu.Unlock()
logObj.rename()
}
}
使用方法
package exampleimport ( "github.com/donnie4w/go-logger/logger" "runtime" "strconv" "testing" "time")func log(i int) { logger.Debug("Debug>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i)) logger.Info("Info>>>>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i)) logger.Warn("Warn>>>>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i)) logger.Error("Error>>>>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i)) logger.Fatal("Fatal>>>>>>>>>>>>>>>>>>>>>>>>>" + strconv.Itoa(i))}func Test(t *testing.T) { runtime.GOMAXPROCS(runtime.NumCPU()) //指定是否控制檯打印,默認爲true logger.SetConsole(true) //指定日誌文件備份方式爲文件大小的方式 //第一個參數爲日誌文件存放目錄 //第二個參數爲日誌文件命名 //第三個參數爲備份文件最大數量 //第四個參數爲備份文件大小 //第五個參數爲文件大小的單位 //logger.SetRollingFile("d:/logtest", "test.log", 10, 5, logger.KB) //指定日誌文件備份方式爲日期的方式 //第一個參數爲日誌文件存放目錄 //第二個參數爲日誌文件命名 logger.SetRollingDaily("d:/logtest", "test.log") //指定日誌級別 ALL,DEBUG,INFO,WARN,ERROR,FATAL,OFF 級別由低到高 //通常習慣是測試階段爲debug,生成環境爲info以上 logger.SetLevel(logger.ERROR) for i := 10000; i > 0; i-- { go log(i) time.Sleep(1000 * time.Millisecond) } time.Sleep(15 * time.Second)}