wangchuanjin 4 жил өмнө
parent
commit
141cc2c379

+ 74 - 0
go-logger/README.md

@@ -0,0 +1,74 @@
+### go-logger 是golang 的日志库 ,基于对golang内置log的封装。
+用法类似java日志工具包log4j
+
+**打印日志有5个方法 Debug,Info,Warn, Error ,Fatal  日志级别由低到高**
+
+设置日志级别的方法为:logger.SetLevel() 如:logger.SetLevel(logger.WARN)
+则:logger.Debug(....),logger.Info(...) 日志不会打出,而 
+ logger.Warn(...),logger.Error(...),logger.Fatal(...)日志会打出。
+设置日志级别的参数有7个,分别为:ALL,DEBUG,INFO,WARN,ERROR,FATAL,OFF
+其中 ALL表示所有调用打印日志的方法都会打出,而OFF则表示都不会打出。
+
+***
+
+日志文件切割有两种类型:1为按日期切分。2为按日志大小切分。
+按日期切分时:每天一个备份日志文件,后缀为 .yyyy-MM-dd 
+过0点是生成前一天备份文件
+
+按大小切分是需要3个参数,1为文件大小,2为单位,3为文件数量
+文件增长到指定限值时,生成备份文件,结尾为依次递增的自然数。
+文件数量增长到指定限制时,新生成的日志文件将覆盖前面生成的同名的备份日志文件。
+
+**示例**:
+
+	//指定是否控制台打印,默认为true
+	logger.SetConsole(true)
+	//指定日志文件备份方式为文件大小的方式
+	//第一个参数为日志文件存放目录
+	//第二个参数为日志文件命名
+	//第三个参数为备份文件最大数量
+	//第四个参数为备份文件大小
+	//第五个参数为文件大小的单位 KB,MB,GB TB
+	//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.DEBUG)
+
+
+### 打印日志:
+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))
+}
+
+
+## v1.0.3
+### 增加
+**1.输出日志格式化,与 log.Printf(format,"***")  format类型,如 **
+  1. logger.SetFormat("%s,%s")  对应参数是两个:logger.Debug("a","b")  输出:a,b 
+
+**2.支持多日志对象,不同对象可以设置不同存放日志目录或日志名称**
+  1. 通用配置 :logger.SetRollingFile() ,logger.SetRollingDaily()
+  2. 指定对象1   		   log1 := logger.GetLogger()   log1.SetRollingDaily("d:/logtest", "t1.log")
+  3. 指定对象2   		   log2 := logger.GetLogger()   log2.SetRollingDaily("d:/logtest", "t2.log")
+
+**3.支持同一对象指定日志级别对应不同文件**
+  1. logger.SetLevelFile(level LEVEL, fileDir, fileName string)
+  2. 参数说明:level 日志级别 ;fileDir 日志文件夹;fileName  日志文件名
+  3. 如:logger.SetLevelFile(logger.INFO, "d:/logtest", "info.log")  
+  4. 如:logger.SetLevelFile(logger.WARN, "d:/logtest", "warn.log")
+
+### 修改
+  1. 重构代码
+  2. 优化,去掉监控器
+
+

+ 60 - 0
go-logger/example/logger_test.go

@@ -0,0 +1,60 @@
+package example
+
+import (
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/donnie4w/go-logger/logger"
+)
+
+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.SetFormat("=====>%s##%s")
+	//指定日志文件备份方式为文件大小的方式
+	//第一个参数为日志文件存放目录
+	//第二个参数为日志文件命名
+	//第三个参数为备份文件最大数量
+	//第四个参数为备份文件大小
+	//第五个参数为文件大小的单位
+	logger.SetRollingFile(`C:\Users\Thinkpad\Desktop\logtest`, "test.log", 10, 1, logger.KB)
+
+	//指定日志文件备份方式为日期的方式
+	//第一个参数为日志文件存放目录
+	//第二个参数为日志文件命名
+	//	logger.SetRollingDaily(`C:\Users\Thinkpad\Desktop\logtest`, "test.log")
+
+	//指定日志级别  ALL,DEBUG,INFO,WARN,ERROR,FATAL,OFF 级别由低到高
+	//一般习惯是测试阶段为debug,		 生成环境为info以上
+	logger.SetLevel(logger.DEBUG)
+
+	for i := 100; i > 0; i-- {
+		go _log(i)
+	}
+	time.Sleep(2 * time.Second)
+	var lg = logger.GetLogger()
+
+	//重新指定log文件
+	lg.SetRollingFile(`C:\Users\Thinkpad\Desktop\logtest`, "test.log", 10, 1, logger.KB)
+	lg.SetLevelFile(logger.INFO, `C:\Users\Thinkpad\Desktop\logtest`, "info.log")
+	lg.SetLevelFile(logger.WARN, `C:\Users\Thinkpad\Desktop\logtest`, "warn.log")
+	lg.Debug("debug hello world")
+	for i := 100; i > 0; i-- {
+		go lg.Info("info hello world >>>>>>>>>>>>>>>>>> ", i)
+	}
+	lg.Warn("warn hello world")
+
+	time.Sleep(2 * time.Second)
+
+}

+ 286 - 0
go-logger/logger/logger.go

@@ -0,0 +1,286 @@
+package logger
+
+//	"log"
+
+const (
+	//go-logger version
+	_VER string = "1.0.3"
+)
+
+type LEVEL int32
+type UNIT int64
+type _ROLLTYPE int //dailyRolling ,rollingFile
+
+const _DATEFORMAT = "2006-01-02"
+
+var logLevel LEVEL = 1
+
+const (
+	_       = iota
+	KB UNIT = 1 << (iota * 10)
+	MB
+	GB
+	TB
+)
+
+const (
+	ALL LEVEL = iota
+	DEBUG
+	INFO
+	WARN
+	ERROR
+	FATAL
+	OFF
+)
+
+const (
+	_DAILY _ROLLTYPE = iota
+	_ROLLFILE
+)
+
+func SetConsole(isConsole bool) {
+	defaultlog.setConsole(isConsole)
+}
+
+func SetLevel(_level LEVEL) {
+	defaultlog.setLevel(_level)
+}
+
+func SetFormat(logFormat string) {
+	defaultlog.setFormat(logFormat)
+}
+
+func SetRollingFile(fileDir, fileName string, maxNumber int32, maxSize int64, _unit UNIT) {
+	//	maxFileCount = maxNumber
+	//	maxFileSize = maxSize * int64(_unit)
+	//	RollingFile = true
+	//	dailyRolling = false
+	//	mkdirlog(fileDir)
+	//	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, 0666)
+	//		logObj.lg = log.New(logObj.logfile, "", log.Ldate|log.Ltime|log.Lshortfile)
+	//	} else {
+	//		logObj.rename()
+	//	}
+	//	go fileMonitor()
+	defaultlog.setRollingFile(fileDir, fileName, maxNumber, maxSize, _unit)
+}
+
+func SetRollingDaily(fileDir, fileName string) {
+	//	RollingFile = false
+	//	dailyRolling = true
+	//	t, _ := time.Parse(_DATEFORMAT, time.Now().Format(_DATEFORMAT))
+	//	mkdirlog(fileDir)
+	//	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, 0666)
+	//		logObj.lg = log.New(logObj.logfile, "", log.Ldate|log.Ltime|log.Lshortfile)
+	//	} else {
+	//		logObj.rename()
+	//	}
+	defaultlog.setRollingDaily(fileDir, fileName)
+}
+
+//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()
+	//	if logObj != nil {
+	//		logObj.mu.RLock()
+	//		defer logObj.mu.RUnlock()
+	//	}
+	//	if logLevel <= DEBUG {
+	//		if logObj != nil {
+	//			logObj.lg.Output(2, fmt.Sprintln("debug", v))
+	//		}
+	//		console("debug", v)
+	//	}
+	defaultlog.debug(v...)
+}
+func Info(v ...interface{}) {
+	//	if dailyRolling {
+	//		fileCheck()
+	//	}
+	//	defer catchError()
+	//	if logObj != nil {
+	//		logObj.mu.RLock()
+	//		defer logObj.mu.RUnlock()
+	//	}
+	//	if logLevel <= INFO {
+	//		if logObj != nil {
+	//			if format == "" {
+	//				logObj.lg.Output(2, fmt.Sprintln("info", v))
+	//			} else {
+	//				logObj.lg.Output(2, fmt.Sprintf(format, v...))
+	//			}
+	//		}
+	//		console("info", v)
+	//	}
+	defaultlog.info(v...)
+}
+func Warn(v ...interface{}) {
+	//	if dailyRolling {
+	//		fileCheck()
+	//	}
+	//	defer catchError()
+	//	if logObj != nil {
+	//		logObj.mu.RLock()
+	//		defer logObj.mu.RUnlock()
+	//	}
+	//	if logLevel <= WARN {
+	//		if logObj != nil {
+	//			logObj.lg.Output(2, fmt.Sprintln("warn", v))
+	//		}
+	//		console("warn", v)
+	//	}
+	defaultlog.warn(v...)
+}
+func Error(v ...interface{}) {
+	//	if dailyRolling {
+	//		fileCheck()
+	//	}
+	//	defer catchError()
+	//	if logObj != nil {
+	//		logObj.mu.RLock()
+	//		defer logObj.mu.RUnlock()
+	//	}
+	//	if logLevel <= ERROR {
+	//		if logObj != nil {
+	//			logObj.lg.Output(2, fmt.Sprintln("error", v))
+	//		}
+	//		console("error", v)
+	//	}
+	defaultlog.error(v...)
+}
+func Fatal(v ...interface{}) {
+	//	if dailyRolling {
+	//		fileCheck()
+	//	}
+	//	defer catchError()
+	//	if logObj != nil {
+	//		logObj.mu.RLock()
+	//		defer logObj.mu.RUnlock()
+	//	}
+	//	if logLevel <= FATAL {
+	//		if logObj != nil {
+	//			logObj.lg.Output(2, fmt.Sprintln("fatal", v))
+	//		}
+	//		console("fatal", v)
+	//	}
+	defaultlog.fatal(v...)
+}
+
+func SetLevelFile(level LEVEL, dir, fileName string) {
+	defaultlog.setLevelFile(level, dir, fileName)
+}
+
+//func 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 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 nextSuffix() int {
+//	return int(f._suffix%int(maxFileCount) + 1)
+//}
+
+//func 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 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()
+//	}
+//}

+ 423 - 0
go-logger/logger/logw.go

@@ -0,0 +1,423 @@
+package logger
+
+import (
+	"crypto/md5"
+	"encoding/hex"
+	"fmt"
+	"log"
+	"os"
+	"runtime"
+	"runtime/debug"
+	"strconv"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+var defaultlog *logBean = getdefaultLogger()
+var skip int = 4
+
+type logger struct {
+	lb *logBean
+}
+
+func (this *logger) SetConsole(isConsole bool) {
+	this.lb.setConsole(isConsole)
+}
+
+func (this *logger) SetLevel(_level LEVEL) {
+	this.lb.setLevel(_level)
+}
+
+func (this *logger) SetFormat(logFormat string) {
+	this.lb.setFormat(logFormat)
+}
+
+func (this *logger) SetRollingFile(fileDir, fileName string, maxNumber int32, maxSize int64, _unit UNIT) {
+	this.lb.setRollingFile(fileDir, fileName, maxNumber, maxSize, _unit)
+}
+
+func (this *logger) SetRollingDaily(fileDir, fileName string) {
+	this.lb.setRollingDaily(fileDir, fileName)
+}
+
+func (this *logger) Debug(v ...interface{}) {
+	this.lb.debug(v...)
+}
+func (this *logger) Info(v ...interface{}) {
+	this.lb.info(v...)
+}
+func (this *logger) Warn(v ...interface{}) {
+	this.lb.warn(v...)
+}
+func (this *logger) Error(v ...interface{}) {
+	this.lb.error(v...)
+}
+func (this *logger) Fatal(v ...interface{}) {
+	this.lb.fatal(v...)
+}
+
+func (this *logger) SetLevelFile(level LEVEL, dir, fileName string) {
+	this.lb.setLevelFile(level, dir, fileName)
+}
+
+type logBean struct {
+	mu              *sync.Mutex
+	logLevel        LEVEL
+	maxFileSize     int64
+	maxFileCount    int32
+	consoleAppender bool
+	rolltype        _ROLLTYPE
+	format          string
+	id              string
+	d, i, w, e, f   string //id
+}
+
+type fileBeanFactory struct {
+	fbs map[string]*fileBean
+	mu  *sync.RWMutex
+}
+
+var fbf = &fileBeanFactory{fbs: make(map[string]*fileBean, 0), mu: new(sync.RWMutex)}
+
+func (this *fileBeanFactory) add(dir, filename string, _suffix int, maxsize int64, maxfileCount int32) {
+	this.mu.Lock()
+	defer this.mu.Unlock()
+	id := md5str(fmt.Sprint(dir, filename))
+	if _, ok := this.fbs[id]; !ok {
+		this.fbs[id] = newFileBean(dir, filename, _suffix, maxsize, maxfileCount)
+	}
+}
+
+func (this *fileBeanFactory) get(id string) *fileBean {
+	this.mu.RLock()
+	defer this.mu.RUnlock()
+	return this.fbs[id]
+}
+
+type fileBean struct {
+	id           string
+	dir          string
+	filename     string
+	_suffix      int
+	_date        *time.Time
+	mu           *sync.RWMutex
+	logfile      *os.File
+	lg           *log.Logger
+	filesize     int64
+	maxFileSize  int64
+	maxFileCount int32
+}
+
+func GetLogger() (l *logger) {
+	l = new(logger)
+	l.lb = getdefaultLogger()
+	return
+}
+
+func getdefaultLogger() (lb *logBean) {
+	lb = &logBean{}
+	lb.mu = new(sync.Mutex)
+	lb.setConsole(true)
+	return
+}
+
+func (this *logBean) setConsole(isConsole bool) {
+	this.consoleAppender = isConsole
+}
+
+func (this *logBean) setLevelFile(level LEVEL, dir, fileName string) {
+	key := md5str(fmt.Sprint(dir, fileName))
+	switch level {
+	case DEBUG:
+		this.d = key
+	case INFO:
+		this.i = key
+	case WARN:
+		this.w = key
+	case ERROR:
+		this.e = key
+	case FATAL:
+		this.f = key
+	default:
+		return
+	}
+	var _suffix = 0
+	if this.maxFileCount < 1<<31-1 {
+		for i := 1; i < int(this.maxFileCount); i++ {
+			if isExist(dir + "/" + fileName + "." + strconv.Itoa(i)) {
+				_suffix = i
+			} else {
+				break
+			}
+		}
+	}
+	fbf.add(dir, fileName, _suffix, this.maxFileSize, this.maxFileCount)
+}
+
+func (this *logBean) setLevel(_level LEVEL) {
+	this.logLevel = _level
+}
+
+func (this *logBean) setFormat(logFormat string) {
+	this.format = logFormat
+}
+
+func (this *logBean) setRollingFile(fileDir, fileName string, maxNumber int32, maxSize int64, _unit UNIT) {
+	this.mu.Lock()
+	defer this.mu.Unlock()
+	if maxNumber > 0 {
+		this.maxFileCount = maxNumber
+	} else {
+		this.maxFileCount = 1<<31 - 1
+	}
+	this.maxFileSize = maxSize * int64(_unit)
+	this.rolltype = _ROLLFILE
+	mkdirlog(fileDir)
+	var _suffix = 0
+	for i := 1; i < int(maxNumber); i++ {
+		if isExist(fileDir + "/" + fileName + "." + strconv.Itoa(i)) {
+			_suffix = i
+		} else {
+			break
+		}
+	}
+	this.id = md5str(fmt.Sprint(fileDir, fileName))
+	fbf.add(fileDir, fileName, _suffix, this.maxFileSize, this.maxFileCount)
+}
+
+func (this *logBean) setRollingDaily(fileDir, fileName string) {
+	this.rolltype = _DAILY
+	mkdirlog(fileDir)
+	this.id = md5str(fmt.Sprint(fileDir, fileName))
+	fbf.add(fileDir, fileName, 0, 0, 0)
+}
+
+func (this *logBean) console(v ...interface{}) {
+	s := fmt.Sprint(v...)
+	if this.consoleAppender {
+		_, file, line, _ := runtime.Caller(skip)
+		short := file
+		for i := len(file) - 1; i > 0; i-- {
+			if file[i] == '/' {
+				short = file[i+1:]
+				break
+			}
+		}
+		file = short
+		if this.format == "" {
+			log.Println(file, strconv.Itoa(line), s)
+		} else {
+			vs := make([]interface{}, 0)
+			vs = append(vs, file)
+			vs = append(vs, strconv.Itoa(line))
+			for _, vv := range v {
+				vs = append(vs, vv)
+			}
+			log.Printf(fmt.Sprint("%s %s ", this.format, "\n"), vs...)
+		}
+	}
+}
+
+func (this *logBean) log(level string, v ...interface{}) {
+	defer catchError()
+	//s := fmt.Sprint(v...)
+	s := ""
+	for _, val := range v {
+		s += " " + fmt.Sprint(val)
+	}
+	length := len([]byte(s))
+	var lg *fileBean = fbf.get(this.id)
+	var _level = ALL
+	switch level {
+	case "debug":
+		if this.d != "" {
+			lg = fbf.get(this.d)
+		}
+		_level = DEBUG
+	case "info":
+		if this.i != "" {
+			lg = fbf.get(this.i)
+		}
+		_level = INFO
+	case "warn":
+		if this.w != "" {
+			lg = fbf.get(this.w)
+		}
+		_level = WARN
+	case "error":
+		if this.e != "" {
+			lg = fbf.get(this.e)
+		}
+		_level = ERROR
+	case "fatal":
+		if this.f != "" {
+			lg = fbf.get(this.f)
+		}
+		_level = FATAL
+	}
+	if lg != nil {
+		this.fileCheck(lg)
+		lg.addsize(int64(length))
+		if this.logLevel <= _level {
+			if lg != nil {
+				if this.format == "" {
+					lg.write(level, s)
+				} else {
+					lg.writef(this.format, v...)
+				}
+			}
+			this.console(v...)
+		}
+	} else {
+		this.console(v...)
+	}
+}
+
+func (this *logBean) debug(v ...interface{}) {
+	this.log("debug", v...)
+}
+func (this *logBean) info(v ...interface{}) {
+	this.log("info", v...)
+}
+func (this *logBean) warn(v ...interface{}) {
+	this.log("warn", v...)
+}
+func (this *logBean) error(v ...interface{}) {
+	this.log("error", v...)
+}
+func (this *logBean) fatal(v ...interface{}) {
+	this.log("fatal", v...)
+}
+
+func (this *logBean) fileCheck(fb *fileBean) {
+	defer catchError()
+	if this.isMustRename(fb) {
+		this.mu.Lock()
+		defer this.mu.Unlock()
+		if this.isMustRename(fb) {
+			fb.rename(this.rolltype)
+		}
+	}
+}
+
+//--------------------------------------------------------------------------------
+
+func (this *logBean) isMustRename(fb *fileBean) bool {
+	switch this.rolltype {
+	case _DAILY:
+		t, _ := time.Parse(_DATEFORMAT, time.Now().Format(_DATEFORMAT))
+		if t.After(*fb._date) {
+			return true
+		}
+	case _ROLLFILE:
+		return fb.isOverSize()
+	}
+	return false
+}
+
+func (this *fileBean) nextSuffix() int {
+	return int(this._suffix%int(this.maxFileCount) + 1)
+}
+
+func newFileBean(fileDir, fileName string, _suffix int, maxSize int64, maxfileCount int32) (fb *fileBean) {
+	t, _ := time.Parse(_DATEFORMAT, time.Now().Format(_DATEFORMAT))
+	fb = &fileBean{dir: fileDir, filename: fileName, _date: &t, mu: new(sync.RWMutex)}
+	fb.logfile, _ = os.OpenFile(fileDir+"/"+fileName, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
+	fb.lg = log.New(fb.logfile, "", log.Ldate|log.Ltime|log.Lshortfile)
+	fb._suffix = _suffix
+	fb.maxFileSize = maxSize
+	fb.maxFileCount = maxfileCount
+	fb.filesize = fileSize(fileDir + "/" + fileName)
+	fb._date = &t
+	return
+}
+
+func (this *fileBean) rename(rolltype _ROLLTYPE) {
+	this.mu.Lock()
+	defer this.mu.Unlock()
+	this.close()
+	nextfilename := ""
+	switch rolltype {
+	case _DAILY:
+		nextfilename = fmt.Sprint(this.dir, "/", this.filename, ".", this._date.Format(_DATEFORMAT))
+	case _ROLLFILE:
+		nextfilename = fmt.Sprint(this.dir, "/", this.filename, ".", this.nextSuffix())
+		this._suffix = this.nextSuffix()
+	}
+	if isExist(nextfilename) {
+		os.Remove(nextfilename)
+	}
+	os.Rename(this.dir+"/"+this.filename, nextfilename)
+	t, _ := time.Parse(_DATEFORMAT, time.Now().Format(_DATEFORMAT))
+	this._date = &t
+	this.logfile, _ = os.OpenFile(this.dir+"/"+this.filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
+	this.lg = log.New(this.logfile, "", log.Ldate|log.Ltime|log.Lshortfile)
+	this.filesize = fileSize(this.dir + "/" + this.filename)
+}
+
+func (this *fileBean) addsize(size int64) {
+	atomic.AddInt64(&this.filesize, size)
+}
+
+func (this *fileBean) write(level string, v ...interface{}) {
+	this.mu.RLock()
+	defer this.mu.RUnlock()
+	s := fmt.Sprint(v...)
+	this.lg.Output(skip+1, fmt.Sprintln(level, s))
+}
+
+func (this *fileBean) writef(format string, v ...interface{}) {
+	this.mu.RLock()
+	defer this.mu.RUnlock()
+	this.lg.Output(skip+1, fmt.Sprintf(format, v...))
+}
+
+func (this *fileBean) isOverSize() bool {
+	return this.filesize >= this.maxFileSize
+}
+
+func (this *fileBean) close() {
+	this.logfile.Close()
+}
+
+//-----------------------------------------------------------------------------------------------
+
+func mkdirlog(dir string) (e error) {
+	_, er := os.Stat(dir)
+	b := er == nil || os.IsExist(er)
+	if !b {
+		if err := os.MkdirAll(dir, 0666); err != nil {
+			if os.IsPermission(err) {
+				e = err
+			}
+		}
+	}
+	return
+}
+
+func fileSize(file string) int64 {
+	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 md5str(s string) string {
+	m := md5.New()
+	m.Write([]byte(s))
+	return hex.EncodeToString(m.Sum(nil))
+}
+
+func catchError() {
+	if err := recover(); err != nil {
+		fmt.Println(string(debug.Stack()))
+	}
+}