日志
package logger
// ==========================
// Admin Vvooooooooooo
// Time 2020/1/7
// Explain log
// ==========================
import (
"fmt"
"log"
"os"
"runtime"
"strconv"
"sync"
"time"
)
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 logObject *_FILE
const DATEFORMAT = "2020-1-7"
type UNIT int64
const (
_ = iota
KB UNIT = 1 << (iota*10)
MB
GB
TB
)
const (
ALL LEVEL = iota
DEBUG
INFO
WARN
ERROR
FATAL
OFF
)
var(
debug_str = "debug"
info_str = "info"
warn_str = "\033[033;1mwarn\033[033;0m"
error_str = "\033[031;1merror\033[031;0m"
fatal_str = "\033[031;1mfatal\033[031;0m"
// \033[字背景颜色;1m(高亮)字符串\033[0m
)
const (
_ = iota
ROLLINGDAILY
ROLLINGFILE
)
func init(){
if runtime.GOOS == "windows"{
warn_str = "warn"
error_str = "error"
fatal_str = "fatal"
}
}
type _FILE struct {
dir string
filename string
_suffix int
isCover bool
_date *time.Time
mu *sync.RWMutex
logfile *os.File
lg *log.Logger
}
//主实现控制台
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("cathError ",err)
}
}
//Debug接口
func Debug(v ...interface{}) {
if dailyRolling {
filecheck()
}
defer catchError()
if logObject != nil{
logObject.mu.RLock()
defer logObject.mu.RUnlock()
}
if logLevel <= DEBUG{
if logObject !=nil{
logObject.lg.Output(2,fmt.Sprintln(debug_str,v))
}
console(debug_str,v)
}
}
//INFO接口
func Info(v ...interface{}) {
if dailyRolling {
filecheck()
}
defer catchError()
if logObject != nil{
logObject.mu.RLock()
defer logObject.mu.RUnlock()
}
if logLevel <= INFO{
if logObject !=nil{
logObject.lg.Output(2,fmt.Sprintln(info_str,v))
}
console(info_str,v)
}
}
//Warn 接口
func Warn(v ...interface{}) {
if dailyRolling {
filecheck()
}
defer catchError()
if logObject != nil {
logObject.mu.RLock()
defer logObject.mu.RUnlock()
}
if logLevel <= WARN {
if logObject != nil {
logObject.lg.Output(2, fmt.Sprintln(warn_str, v))
}
console(warn_str, v)
}
}
//Error 接口
func Error(v ...interface{}) {
if dailyRolling {
filecheck()
}
defer catchError()
if logObject != nil {
logObject.mu.RLock()
defer logObject.mu.RUnlock()
}
if logLevel <= ERROR {
if logObject != nil {
logObject.lg.Output(2, fmt.Sprintln(error_str, v))
}
console(error_str, v)
}
}
//Fatal 接口
func Fatal(v ...interface{}) {
if dailyRolling {
filecheck()
}
defer catchError()
if logObject != nil {
logObject.mu.RLock()
defer logObject.mu.RUnlock()
}
if logLevel <= FATAL {
if logObject != nil {
logObject.lg.Output(2, fmt.Sprintln(fatal_str, v))
}
console(fatal_str, v)
}
}
//底层实现
func SetPrefix(title string){
log.SetPrefix(title)
}
func SetConsole(isConsole bool){
consoleAppender = isConsole
}
func SetLevel(_level LEVEL){
logLevel = _level
}
func SetRollingFile(fileDir,filename string,maxNum int32,maxSize int64,_unit UNIT){
maxFileCount = maxNum
maxFileSize = maxSize
RollingFile = true
dailyRolling = false
mkdirlog(fileDir)
logObject = &_FILE{dir:fileDir,filename:filename,isCover:false,mu:new(sync.RWMutex)}
logObject.mu.Lock()
defer logObject.mu.Unlock()
for i:=1;i<int(maxNum);i++{
if isExist(fileDir+"/"+filename+"."+strconv.Itoa(i)){
logObject._suffix = i
}else{
break
}
}
if !logObject.isMustRename(){
logObject.logfile,_ = os.OpenFile(fileDir+"/"+filename,os.O_RDWR|os.O_APPEND|os.O_CREATE,06666)
logObject.lg = log.New(logObject.logfile,"",log.Ldate|log.Ltime|log.Lshortfile)
}else{
logObject.rename()
}
go fileMonitor()
}
func SetRollingDaily(fileDir,fileName string){
RollingFile = false
dailyRolling =true
t,_ := time.Parse(DATEFORMAT,time.Now().Format(DATEFORMAT))
mkdirlog(fileDir)
logObject = &_FILE{dir:fileDir,filename:fileName,_date:&t,isCover:false,mu:new(sync.RWMutex)}
logObject.mu.Lock()
defer logObject.mu.Unlock()
if !logObject.isMustRename(){
logObject.logfile,_ = os.OpenFile(fileDir+"/"+fileName,os.O_RDWR|os.O_APPEND|os.O_CREATE,06666)
logObject.lg = log.New(logObject.logfile,"",log.Ldate|log.Ltime|log.Lshortfile)
}else{
logObject.rename()
}
}
func mkdirlog(dir string)(e error){
_,err :=os.Stat(dir)
b:=err ==nil || os.IsExist(err)
if !b {
if new_err := os.MkdirAll(dir,06666);new_err !=nil{
if os.IsPermission(new_err){
fmt.Println("VV create logger dir error :",new_err.Error())
e = new_err
}
}
}
return
}
func isExist(path string) bool {
_,err := os.Stat(path)
return err ==nil || os.IsExist(err)
}
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 errr",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(logObject.logfile,"",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()
}
var path = f.dir+"/"+f.filename+"."+strconv.Itoa(int(f._suffix))
if isExist(path){
os.Remove(path)
}
os.Rename(f.dir+"/"+f.filename,path)
f.logfile,_ =os.Create(f.dir+"/"+f.filename)
f.lg = log.New(logObject.logfile,"",log.Ldate|log.Ltime|log.Lshortfile)
}
func fileSize(file string) int64{
fmt.Println("VV FileSize ",file)
f,err := os.Stat(file)
if err!=nil{
fmt.Println(err.Error())
return 0
}
return f.Size()
}
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 logObject !=nil && logObject.isMustRename(){
logObject.mu.Lock();
defer logObject.mu.Unlock()
logObject.rename()
}
}